linux/drivers/staging/speakup/main.c
<<
>>
Prefs
   1/* speakup.c
   2 * review functions for the speakup screen review package.
   3 * originally written by: Kirk Reiser and Andy Berdan.
   4 *
   5 * extensively modified by David Borowski.
   6 *
   7 ** Copyright (C) 1998  Kirk Reiser.
   8 *  Copyright (C) 2003  David Borowski.
   9 *
  10 *  This program is free software; you can redistribute it and/or modify
  11 *  it under the terms of the GNU General Public License as published by
  12 *  the Free Software Foundation; either version 2 of the License, or
  13 *  (at your option) any later version.
  14 *
  15 *  This program is distributed in the hope that it will be useful,
  16 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 *  GNU General Public License for more details.
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/vt.h>
  23#include <linux/tty.h>
  24#include <linux/mm.h>           /* __get_free_page() and friends */
  25#include <linux/vt_kern.h>
  26#include <linux/ctype.h>
  27#include <linux/selection.h>
  28#include <linux/unistd.h>
  29#include <linux/jiffies.h>
  30#include <linux/kthread.h>
  31#include <linux/keyboard.h>     /* for KT_SHIFT */
  32#include <linux/kbd_kern.h>     /* for vc_kbd_* and friends */
  33#include <linux/input.h>
  34#include <linux/kmod.h>
  35
  36/* speakup_*_selection */
  37#include <linux/module.h>
  38#include <linux/sched.h>
  39#include <linux/slab.h>
  40#include <linux/types.h>
  41#include <linux/consolemap.h>
  42
  43#include <linux/spinlock.h>
  44#include <linux/notifier.h>
  45
  46#include <linux/uaccess.h>      /* copy_from|to|user() and others */
  47
  48#include "spk_priv.h"
  49#include "speakup.h"
  50
  51#define MAX_DELAY msecs_to_jiffies(500)
  52#define MINECHOCHAR SPACE
  53
  54MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
  55MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
  56MODULE_DESCRIPTION("Speakup console speech");
  57MODULE_LICENSE("GPL");
  58MODULE_VERSION(SPEAKUP_VERSION);
  59
  60char *synth_name;
  61module_param_named(synth, synth_name, charp, 0444);
  62module_param_named(quiet, spk_quiet_boot, bool, 0444);
  63
  64MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
  65MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
  66
  67special_func spk_special_handler;
  68
  69short spk_pitch_shift, synth_flags;
  70static char buf[256];
  71int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
  72int spk_no_intr, spk_spell_delay;
  73int spk_key_echo, spk_say_word_ctl;
  74int spk_say_ctrl, spk_bell_pos;
  75short spk_punc_mask;
  76int spk_punc_level, spk_reading_punc;
  77char spk_str_caps_start[MAXVARLEN + 1] = "\0";
  78char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
  79const struct st_bits_data spk_punc_info[] = {
  80        {"none", "", 0},
  81        {"some", "/$%&@", SOME},
  82        {"most", "$%&#()=+*/@^<>|\\", MOST},
  83        {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
  84        {"delimiters", "", B_WDLM},
  85        {"repeats", "()", CH_RPT},
  86        {"extended numeric", "", B_EXNUM},
  87        {"symbols", "", B_SYM},
  88        {NULL, NULL}
  89};
  90
  91static char mark_cut_flag;
  92#define MAX_KEY 160
  93static u_char *spk_shift_table;
  94u_char *spk_our_keys[MAX_KEY];
  95u_char spk_key_buf[600];
  96const u_char spk_key_defaults[] = {
  97#include "speakupmap.h"
  98};
  99
 100/* Speakup Cursor Track Variables */
 101static int cursor_track = 1, prev_cursor_track = 1;
 102
 103/* cursor track modes, must be ordered same as cursor_msgs */
 104enum {
 105        CT_Off = 0,
 106        CT_On,
 107        CT_Highlight,
 108        CT_Window,
 109        CT_Max
 110};
 111#define read_all_mode CT_Max
 112
 113static struct tty_struct *tty;
 114
 115static void spkup_write(const char *in_buf, int count);
 116
 117static char *phonetic[] = {
 118        "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
 119        "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
 120            "papa",
 121        "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
 122        "x ray", "yankee", "zulu"
 123};
 124
 125/* array of 256 char pointers (one for each character description)
 126 * initialized to default_chars and user selectable via
 127 * /proc/speakup/characters
 128 */
 129char *spk_characters[256];
 130
 131char *spk_default_chars[256] = {
 132/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
 133/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
 134/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
 135/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
 136            "control",
 137/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
 138            "tick",
 139/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
 140            "dot",
 141        "slash",
 142/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
 143        "eight", "nine",
 144/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
 145/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
 146/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
 147/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
 148/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
 149            "caret",
 150        "line",
 151/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
 152/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
 153/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
 154/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
 155/*127*/ "del", "control", "control", "control", "control", "control",
 156            "control", "control", "control", "control", "control",
 157/*138*/ "control", "control", "control", "control", "control",
 158            "control", "control", "control", "control", "control",
 159            "control", "control",
 160/*150*/ "control", "control", "control", "control", "control",
 161            "control", "control", "control", "control", "control",
 162/*160*/ "nbsp", "inverted bang",
 163/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
 164/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
 165/*172*/ "not", "soft hyphen", "registered", "macron",
 166/*176*/ "degrees", "plus or minus", "super two", "super three",
 167/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
 168/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
 169/*188*/ "one quarter", "one half", "three quarters",
 170            "inverted question",
 171/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
 172            "A RING",
 173/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
 174            "E OOMLAUT",
 175/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
 176            "N TILDE",
 177/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
 178/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
 179            "U CIRCUMFLEX",
 180/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
 181/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
 182/*230*/ "ae", "c cidella", "e grave", "e acute",
 183/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
 184            "i circumflex",
 185/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
 186            "o circumflex",
 187/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
 188            "u acute",
 189/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
 190};
 191
 192/* array of 256 u_short (one for each character)
 193 * initialized to default_chartab and user selectable via
 194 * /sys/module/speakup/parameters/chartab
 195 */
 196u_short spk_chartab[256];
 197
 198static u_short default_chartab[256] = {
 199        B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
 200        B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
 201        B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
 202        B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
 203        WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,     /*  !"#$%&' */
 204        PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,   /* ()*+, -./ */
 205        NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
 206        NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,       /* 89:;<=>? */
 207        PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,  /* @ABCDEFG */
 208        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
 209        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
 210        A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,      /* XYZ[\]^_ */
 211        PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,  /* `abcdefg */
 212        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
 213        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
 214        ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
 215        B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
 216        B_SYM,  /* 135 */
 217        B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
 218        B_CAPSYM,       /* 143 */
 219        B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
 220        B_SYM,  /* 151 */
 221        B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
 222        B_SYM,  /* 159 */
 223        WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
 224        B_SYM,  /* 167 */
 225        B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
 226        B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
 227        B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
 228        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
 229        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
 230        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
 231        A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
 232        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
 233        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
 234        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
 235        ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA  /* 248-255 */
 236};
 237
 238struct task_struct *speakup_task;
 239struct bleep spk_unprocessed_sound;
 240static int spk_keydown;
 241static u_char spk_lastkey, spk_close_press, keymap_flags;
 242static u_char last_keycode, this_speakup_key;
 243static u_long last_spk_jiffy;
 244
 245struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
 246
 247DEFINE_MUTEX(spk_mutex);
 248
 249static int keyboard_notifier_call(struct notifier_block *,
 250                                  unsigned long code, void *param);
 251
 252static struct notifier_block keyboard_notifier_block = {
 253        .notifier_call = keyboard_notifier_call,
 254};
 255
 256static int vt_notifier_call(struct notifier_block *,
 257                            unsigned long code, void *param);
 258
 259static struct notifier_block vt_notifier_block = {
 260        .notifier_call = vt_notifier_call,
 261};
 262
 263static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
 264{
 265        pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
 266        return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
 267}
 268
 269static void speakup_date(struct vc_data *vc)
 270{
 271        spk_x = spk_cx = vc->vc_x;
 272        spk_y = spk_cy = vc->vc_y;
 273        spk_pos = spk_cp = vc->vc_pos;
 274        spk_old_attr = spk_attr;
 275        spk_attr = get_attributes(vc, (u_short *)spk_pos);
 276}
 277
 278static void bleep(u_short val)
 279{
 280        static const short vals[] = {
 281                350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
 282        };
 283        short freq;
 284        int time = spk_bleep_time;
 285
 286        freq = vals[val % 12];
 287        if (val > 11)
 288                freq *= (1 << (val / 12));
 289        spk_unprocessed_sound.freq = freq;
 290        spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
 291        spk_unprocessed_sound.active = 1;
 292        /* We can only have 1 active sound at a time. */
 293}
 294
 295static void speakup_shut_up(struct vc_data *vc)
 296{
 297        if (spk_killed)
 298                return;
 299        spk_shut_up |= 0x01;
 300        spk_parked &= 0xfe;
 301        speakup_date(vc);
 302        if (synth != NULL)
 303                spk_do_flush();
 304}
 305
 306static void speech_kill(struct vc_data *vc)
 307{
 308        char val = synth->is_alive(synth);
 309
 310        if (val == 0)
 311                return;
 312
 313        /* re-enables synth, if disabled */
 314        if (val == 2 || spk_killed) {
 315                /* dead */
 316                spk_shut_up &= ~0x40;
 317                synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
 318        } else {
 319                synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
 320                spk_shut_up |= 0x40;
 321        }
 322}
 323
 324static void speakup_off(struct vc_data *vc)
 325{
 326        if (spk_shut_up & 0x80) {
 327                spk_shut_up &= 0x7f;
 328                synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
 329        } else {
 330                spk_shut_up |= 0x80;
 331                synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
 332        }
 333        speakup_date(vc);
 334}
 335
 336static void speakup_parked(struct vc_data *vc)
 337{
 338        if (spk_parked & 0x80) {
 339                spk_parked = 0;
 340                synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
 341        } else {
 342                spk_parked |= 0x80;
 343                synth_printf("%s\n", spk_msg_get(MSG_PARKED));
 344        }
 345}
 346
 347static void speakup_cut(struct vc_data *vc)
 348{
 349        static const char err_buf[] = "set selection failed";
 350        int ret;
 351
 352        if (!mark_cut_flag) {
 353                mark_cut_flag = 1;
 354                spk_xs = (u_short)spk_x;
 355                spk_ys = (u_short)spk_y;
 356                spk_sel_cons = vc;
 357                synth_printf("%s\n", spk_msg_get(MSG_MARK));
 358                return;
 359        }
 360        spk_xe = (u_short)spk_x;
 361        spk_ye = (u_short)spk_y;
 362        mark_cut_flag = 0;
 363        synth_printf("%s\n", spk_msg_get(MSG_CUT));
 364
 365        speakup_clear_selection();
 366        ret = speakup_set_selection(tty);
 367
 368        switch (ret) {
 369        case 0:
 370                break;          /* no error */
 371        case -EFAULT:
 372                pr_warn("%sEFAULT\n", err_buf);
 373                break;
 374        case -EINVAL:
 375                pr_warn("%sEINVAL\n", err_buf);
 376                break;
 377        case -ENOMEM:
 378                pr_warn("%sENOMEM\n", err_buf);
 379                break;
 380        }
 381}
 382
 383static void speakup_paste(struct vc_data *vc)
 384{
 385        if (mark_cut_flag) {
 386                mark_cut_flag = 0;
 387                synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
 388        } else {
 389                synth_printf("%s\n", spk_msg_get(MSG_PASTE));
 390                speakup_paste_selection(tty);
 391        }
 392}
 393
 394static void say_attributes(struct vc_data *vc)
 395{
 396        int fg = spk_attr & 0x0f;
 397        int bg = spk_attr >> 4;
 398
 399        if (fg > 8) {
 400                synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
 401                fg -= 8;
 402        }
 403        synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
 404        if (bg > 7) {
 405                synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
 406                bg -= 8;
 407        } else
 408                synth_printf(" %s ", spk_msg_get(MSG_ON));
 409        synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
 410}
 411
 412enum {
 413        edge_top = 1,
 414        edge_bottom,
 415        edge_left,
 416        edge_right,
 417        edge_quiet
 418};
 419
 420static void announce_edge(struct vc_data *vc, int msg_id)
 421{
 422        if (spk_bleeps & 1)
 423                bleep(spk_y);
 424        if ((spk_bleeps & 2) && (msg_id < edge_quiet))
 425                synth_printf("%s\n",
 426                        spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
 427}
 428
 429static void speak_char(u_char ch)
 430{
 431        char *cp = spk_characters[ch];
 432        struct var_t *direct = spk_get_var(DIRECT);
 433
 434        if (direct && direct->u.n.value) {
 435                if (IS_CHAR(ch, B_CAP)) {
 436                        spk_pitch_shift++;
 437                        synth_printf("%s", spk_str_caps_start);
 438                }
 439                synth_printf("%c", ch);
 440                if (IS_CHAR(ch, B_CAP))
 441                        synth_printf("%s", spk_str_caps_stop);
 442                return;
 443        }
 444        if (cp == NULL) {
 445                pr_info("speak_char: cp == NULL!\n");
 446                return;
 447        }
 448        synth_buffer_add(SPACE);
 449        if (IS_CHAR(ch, B_CAP)) {
 450                spk_pitch_shift++;
 451                synth_printf("%s", spk_str_caps_start);
 452                synth_printf("%s", cp);
 453                synth_printf("%s", spk_str_caps_stop);
 454        } else {
 455                if (*cp == '^') {
 456                        synth_printf("%s", spk_msg_get(MSG_CTRL));
 457                        cp++;
 458                }
 459                synth_printf("%s", cp);
 460        }
 461        synth_buffer_add(SPACE);
 462}
 463
 464static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
 465{
 466        u16 ch = ' ';
 467
 468        if (vc && pos) {
 469                u16 w;
 470                u16 c;
 471
 472                pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
 473                w = scr_readw(pos);
 474                c = w & 0xff;
 475
 476                if (w & vc->vc_hi_font_mask) {
 477                        w &= ~vc->vc_hi_font_mask;
 478                        c |= 0x100;
 479                }
 480
 481                ch = inverse_translate(vc, c, 0);
 482                *attribs = (w & 0xff00) >> 8;
 483        }
 484        return ch;
 485}
 486
 487static void say_char(struct vc_data *vc)
 488{
 489        u_short ch;
 490
 491        spk_old_attr = spk_attr;
 492        ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
 493        if (spk_attr != spk_old_attr) {
 494                if (spk_attrib_bleep & 1)
 495                        bleep(spk_y);
 496                if (spk_attrib_bleep & 2)
 497                        say_attributes(vc);
 498        }
 499        speak_char(ch & 0xff);
 500}
 501
 502static void say_phonetic_char(struct vc_data *vc)
 503{
 504        u_short ch;
 505
 506        spk_old_attr = spk_attr;
 507        ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
 508        if (isascii(ch) && isalpha(ch)) {
 509                ch &= 0x1f;
 510                synth_printf("%s\n", phonetic[--ch]);
 511        } else {
 512                if (IS_CHAR(ch, B_NUM))
 513                        synth_printf("%s ", spk_msg_get(MSG_NUMBER));
 514                speak_char(ch);
 515        }
 516}
 517
 518static void say_prev_char(struct vc_data *vc)
 519{
 520        spk_parked |= 0x01;
 521        if (spk_x == 0) {
 522                announce_edge(vc, edge_left);
 523                return;
 524        }
 525        spk_x--;
 526        spk_pos -= 2;
 527        say_char(vc);
 528}
 529
 530static void say_next_char(struct vc_data *vc)
 531{
 532        spk_parked |= 0x01;
 533        if (spk_x == vc->vc_cols - 1) {
 534                announce_edge(vc, edge_right);
 535                return;
 536        }
 537        spk_x++;
 538        spk_pos += 2;
 539        say_char(vc);
 540}
 541
 542/* get_word - will first check to see if the character under the
 543 * reading cursor is a space and if spk_say_word_ctl is true it will
 544 * return the word space.  If spk_say_word_ctl is not set it will check to
 545 * see if there is a word starting on the next position to the right
 546 * and return that word if it exists.  If it does not exist it will
 547 * move left to the beginning of any previous word on the line or the
 548 * beginning off the line whichever comes first..
 549 */
 550
 551static u_long get_word(struct vc_data *vc)
 552{
 553        u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
 554        char ch;
 555        u_short attr_ch;
 556        u_char temp;
 557
 558        spk_old_attr = spk_attr;
 559        ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
 560
 561/* decided to take out the sayword if on a space (mis-information */
 562        if (spk_say_word_ctl && ch == SPACE) {
 563                *buf = '\0';
 564                synth_printf("%s\n", spk_msg_get(MSG_SPACE));
 565                return 0;
 566        } else if ((tmpx < vc->vc_cols - 2)
 567                   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
 568                   && ((char)get_char(vc, (u_short *)&tmp_pos + 1, &temp) >
 569                       SPACE)) {
 570                tmp_pos += 2;
 571                tmpx++;
 572        } else
 573                while (tmpx > 0) {
 574                        ch = (char)get_char(vc, (u_short *)tmp_pos - 1, &temp);
 575                        if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
 576                            && ((char)get_char(vc, (u_short *)tmp_pos, &temp) >
 577                                SPACE))
 578                                break;
 579                        tmp_pos -= 2;
 580                        tmpx--;
 581                }
 582        attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
 583        buf[cnt++] = attr_ch & 0xff;
 584        while (tmpx < vc->vc_cols - 1) {
 585                tmp_pos += 2;
 586                tmpx++;
 587                ch = (char)get_char(vc, (u_short *)tmp_pos, &temp);
 588                if ((ch == SPACE) || ch == 0
 589                    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
 590                        break;
 591                buf[cnt++] = ch;
 592        }
 593        buf[cnt] = '\0';
 594        return cnt;
 595}
 596
 597static void say_word(struct vc_data *vc)
 598{
 599        u_long cnt = get_word(vc);
 600        u_short saved_punc_mask = spk_punc_mask;
 601
 602        if (cnt == 0)
 603                return;
 604        spk_punc_mask = PUNC;
 605        buf[cnt++] = SPACE;
 606        spkup_write(buf, cnt);
 607        spk_punc_mask = saved_punc_mask;
 608}
 609
 610static void say_prev_word(struct vc_data *vc)
 611{
 612        u_char temp;
 613        char ch;
 614        u_short edge_said = 0, last_state = 0, state = 0;
 615
 616        spk_parked |= 0x01;
 617
 618        if (spk_x == 0) {
 619                if (spk_y == 0) {
 620                        announce_edge(vc, edge_top);
 621                        return;
 622                }
 623                spk_y--;
 624                spk_x = vc->vc_cols;
 625                edge_said = edge_quiet;
 626        }
 627        while (1) {
 628                if (spk_x == 0) {
 629                        if (spk_y == 0) {
 630                                edge_said = edge_top;
 631                                break;
 632                        }
 633                        if (edge_said != edge_quiet)
 634                                edge_said = edge_left;
 635                        if (state > 0)
 636                                break;
 637                        spk_y--;
 638                        spk_x = vc->vc_cols - 1;
 639                } else
 640                        spk_x--;
 641                spk_pos -= 2;
 642                ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
 643                if (ch == SPACE || ch == 0)
 644                        state = 0;
 645                else if (IS_WDLM(ch))
 646                        state = 1;
 647                else
 648                        state = 2;
 649                if (state < last_state) {
 650                        spk_pos += 2;
 651                        spk_x++;
 652                        break;
 653                }
 654                last_state = state;
 655        }
 656        if (spk_x == 0 && edge_said == edge_quiet)
 657                edge_said = edge_left;
 658        if (edge_said > 0 && edge_said < edge_quiet)
 659                announce_edge(vc, edge_said);
 660        say_word(vc);
 661}
 662
 663static void say_next_word(struct vc_data *vc)
 664{
 665        u_char temp;
 666        char ch;
 667        u_short edge_said = 0, last_state = 2, state = 0;
 668
 669        spk_parked |= 0x01;
 670        if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
 671                announce_edge(vc, edge_bottom);
 672                return;
 673        }
 674        while (1) {
 675                ch = (char)get_char(vc, (u_short *)spk_pos, &temp);
 676                if (ch == SPACE || ch == 0)
 677                        state = 0;
 678                else if (IS_WDLM(ch))
 679                        state = 1;
 680                else
 681                        state = 2;
 682                if (state > last_state)
 683                        break;
 684                if (spk_x >= vc->vc_cols - 1) {
 685                        if (spk_y == vc->vc_rows - 1) {
 686                                edge_said = edge_bottom;
 687                                break;
 688                        }
 689                        state = 0;
 690                        spk_y++;
 691                        spk_x = 0;
 692                        edge_said = edge_right;
 693                } else
 694                        spk_x++;
 695                spk_pos += 2;
 696                last_state = state;
 697        }
 698        if (edge_said > 0)
 699                announce_edge(vc, edge_said);
 700        say_word(vc);
 701}
 702
 703static void spell_word(struct vc_data *vc)
 704{
 705        static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
 706        char *cp = buf, *str_cap = spk_str_caps_stop;
 707        char *cp1, *last_cap = spk_str_caps_stop;
 708        u_char ch;
 709
 710        if (!get_word(vc))
 711                return;
 712        while ((ch = (u_char)*cp)) {
 713                if (cp != buf)
 714                        synth_printf(" %s ", delay_str[spk_spell_delay]);
 715                if (IS_CHAR(ch, B_CAP)) {
 716                        str_cap = spk_str_caps_start;
 717                        if (*spk_str_caps_stop)
 718                                spk_pitch_shift++;
 719                        else    /* synth has no pitch */
 720                                last_cap = spk_str_caps_stop;
 721                } else
 722                        str_cap = spk_str_caps_stop;
 723                if (str_cap != last_cap) {
 724                        synth_printf("%s", str_cap);
 725                        last_cap = str_cap;
 726                }
 727                if (this_speakup_key == SPELL_PHONETIC
 728                    && (isascii(ch) && isalpha(ch))) {
 729                        ch &= 31;
 730                        cp1 = phonetic[--ch];
 731                } else {
 732                        cp1 = spk_characters[ch];
 733                        if (*cp1 == '^') {
 734                                synth_printf("%s", spk_msg_get(MSG_CTRL));
 735                                cp1++;
 736                        }
 737                }
 738                synth_printf("%s", cp1);
 739                cp++;
 740        }
 741        if (str_cap != spk_str_caps_stop)
 742                synth_printf("%s", spk_str_caps_stop);
 743}
 744
 745static int get_line(struct vc_data *vc)
 746{
 747        u_long tmp = spk_pos - (spk_x * 2);
 748        int i = 0;
 749        u_char tmp2;
 750
 751        spk_old_attr = spk_attr;
 752        spk_attr = get_attributes(vc, (u_short *)spk_pos);
 753        for (i = 0; i < vc->vc_cols; i++) {
 754                buf[i] = (u_char)get_char(vc, (u_short *)tmp, &tmp2);
 755                tmp += 2;
 756        }
 757        for (--i; i >= 0; i--)
 758                if (buf[i] != SPACE)
 759                        break;
 760        return ++i;
 761}
 762
 763static void say_line(struct vc_data *vc)
 764{
 765        int i = get_line(vc);
 766        char *cp;
 767        u_short saved_punc_mask = spk_punc_mask;
 768
 769        if (i == 0) {
 770                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 771                return;
 772        }
 773        buf[i++] = '\n';
 774        if (this_speakup_key == SAY_LINE_INDENT) {
 775                cp = buf;
 776                while (*cp == SPACE)
 777                        cp++;
 778                synth_printf("%d, ", (cp - buf) + 1);
 779        }
 780        spk_punc_mask = spk_punc_masks[spk_reading_punc];
 781        spkup_write(buf, i);
 782        spk_punc_mask = saved_punc_mask;
 783}
 784
 785static void say_prev_line(struct vc_data *vc)
 786{
 787        spk_parked |= 0x01;
 788        if (spk_y == 0) {
 789                announce_edge(vc, edge_top);
 790                return;
 791        }
 792        spk_y--;
 793        spk_pos -= vc->vc_size_row;
 794        say_line(vc);
 795}
 796
 797static void say_next_line(struct vc_data *vc)
 798{
 799        spk_parked |= 0x01;
 800        if (spk_y == vc->vc_rows - 1) {
 801                announce_edge(vc, edge_bottom);
 802                return;
 803        }
 804        spk_y++;
 805        spk_pos += vc->vc_size_row;
 806        say_line(vc);
 807}
 808
 809static int say_from_to(struct vc_data *vc, u_long from, u_long to,
 810                       int read_punc)
 811{
 812        int i = 0;
 813        u_char tmp;
 814        u_short saved_punc_mask = spk_punc_mask;
 815
 816        spk_old_attr = spk_attr;
 817        spk_attr = get_attributes(vc, (u_short *)from);
 818        while (from < to) {
 819                buf[i++] = (char)get_char(vc, (u_short *)from, &tmp);
 820                from += 2;
 821                if (i >= vc->vc_size_row)
 822                        break;
 823        }
 824        for (--i; i >= 0; i--)
 825                if (buf[i] != SPACE)
 826                        break;
 827        buf[++i] = SPACE;
 828        buf[++i] = '\0';
 829        if (i < 1)
 830                return i;
 831        if (read_punc)
 832                spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
 833        spkup_write(buf, i);
 834        if (read_punc)
 835                spk_punc_mask = saved_punc_mask;
 836        return i - 1;
 837}
 838
 839static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
 840                             int read_punc)
 841{
 842        u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
 843        u_long end = start + (to * 2);
 844
 845        start += from * 2;
 846        if (say_from_to(vc, start, end, read_punc) <= 0)
 847                if (cursor_track != read_all_mode)
 848                        synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 849}
 850
 851/* Sentence Reading Commands */
 852
 853static int currsentence;
 854static int numsentences[2];
 855static char *sentbufend[2];
 856static char *sentmarks[2][10];
 857static int currbuf;
 858static int bn;
 859static char sentbuf[2][256];
 860
 861static int say_sentence_num(int num, int prev)
 862{
 863        bn = currbuf;
 864        currsentence = num + 1;
 865        if (prev && --bn == -1)
 866                bn = 1;
 867
 868        if (num > numsentences[bn])
 869                return 0;
 870
 871        spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
 872        return 1;
 873}
 874
 875static int get_sentence_buf(struct vc_data *vc, int read_punc)
 876{
 877        u_long start, end;
 878        int i, bn;
 879        u_char tmp;
 880
 881        currbuf++;
 882        if (currbuf == 2)
 883                currbuf = 0;
 884        bn = currbuf;
 885        start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
 886        end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
 887
 888        numsentences[bn] = 0;
 889        sentmarks[bn][0] = &sentbuf[bn][0];
 890        i = 0;
 891        spk_old_attr = spk_attr;
 892        spk_attr = get_attributes(vc, (u_short *)start);
 893
 894        while (start < end) {
 895                sentbuf[bn][i] = (char)get_char(vc, (u_short *)start, &tmp);
 896                if (i > 0) {
 897                        if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
 898                            && numsentences[bn] < 9) {
 899                                /* Sentence Marker */
 900                                numsentences[bn]++;
 901                                sentmarks[bn][numsentences[bn]] =
 902                                    &sentbuf[bn][i];
 903                        }
 904                }
 905                i++;
 906                start += 2;
 907                if (i >= vc->vc_size_row)
 908                        break;
 909        }
 910
 911        for (--i; i >= 0; i--)
 912                if (sentbuf[bn][i] != SPACE)
 913                        break;
 914
 915        if (i < 1)
 916                return -1;
 917
 918        sentbuf[bn][++i] = SPACE;
 919        sentbuf[bn][++i] = '\0';
 920
 921        sentbufend[bn] = &sentbuf[bn][i];
 922        return numsentences[bn];
 923}
 924
 925static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
 926{
 927        u_long start = vc->vc_origin, end;
 928
 929        if (from > 0)
 930                start += from * vc->vc_size_row;
 931        if (to > vc->vc_rows)
 932                to = vc->vc_rows;
 933        end = vc->vc_origin + (to * vc->vc_size_row);
 934        for (from = start; from < end; from = to) {
 935                to = from + vc->vc_size_row;
 936                say_from_to(vc, from, to, 1);
 937        }
 938}
 939
 940static void say_screen(struct vc_data *vc)
 941{
 942        say_screen_from_to(vc, 0, vc->vc_rows);
 943}
 944
 945static void speakup_win_say(struct vc_data *vc)
 946{
 947        u_long start, end, from, to;
 948
 949        if (win_start < 2) {
 950                synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
 951                return;
 952        }
 953        start = vc->vc_origin + (win_top * vc->vc_size_row);
 954        end = vc->vc_origin + (win_bottom * vc->vc_size_row);
 955        while (start <= end) {
 956                from = start + (win_left * 2);
 957                to = start + (win_right * 2);
 958                say_from_to(vc, from, to, 1);
 959                start += vc->vc_size_row;
 960        }
 961}
 962
 963static void top_edge(struct vc_data *vc)
 964{
 965        spk_parked |= 0x01;
 966        spk_pos = vc->vc_origin + 2 * spk_x;
 967        spk_y = 0;
 968        say_line(vc);
 969}
 970
 971static void bottom_edge(struct vc_data *vc)
 972{
 973        spk_parked |= 0x01;
 974        spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
 975        spk_y = vc->vc_rows - 1;
 976        say_line(vc);
 977}
 978
 979static void left_edge(struct vc_data *vc)
 980{
 981        spk_parked |= 0x01;
 982        spk_pos -= spk_x * 2;
 983        spk_x = 0;
 984        say_char(vc);
 985}
 986
 987static void right_edge(struct vc_data *vc)
 988{
 989        spk_parked |= 0x01;
 990        spk_pos += (vc->vc_cols - spk_x - 1) * 2;
 991        spk_x = vc->vc_cols - 1;
 992        say_char(vc);
 993}
 994
 995static void say_first_char(struct vc_data *vc)
 996{
 997        int i, len = get_line(vc);
 998        u_char ch;
 999
1000        spk_parked |= 0x01;
1001        if (len == 0) {
1002                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1003                return;
1004        }
1005        for (i = 0; i < len; i++)
1006                if (buf[i] != SPACE)
1007                        break;
1008        ch = buf[i];
1009        spk_pos -= (spk_x - i) * 2;
1010        spk_x = i;
1011        synth_printf("%d, ", ++i);
1012        speak_char(ch);
1013}
1014
1015static void say_last_char(struct vc_data *vc)
1016{
1017        int len = get_line(vc);
1018        u_char ch;
1019
1020        spk_parked |= 0x01;
1021        if (len == 0) {
1022                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1023                return;
1024        }
1025        ch = buf[--len];
1026        spk_pos -= (spk_x - len) * 2;
1027        spk_x = len;
1028        synth_printf("%d, ", ++len);
1029        speak_char(ch);
1030}
1031
1032static void say_position(struct vc_data *vc)
1033{
1034        synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1035                     vc->vc_num + 1);
1036        synth_printf("\n");
1037}
1038
1039/* Added by brianb */
1040static void say_char_num(struct vc_data *vc)
1041{
1042        u_char tmp;
1043        u_short ch = get_char(vc, (u_short *)spk_pos, &tmp);
1044
1045        ch &= 0xff;
1046        synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1047}
1048
1049/* these are stub functions to keep keyboard.c happy. */
1050
1051static void say_from_top(struct vc_data *vc)
1052{
1053        say_screen_from_to(vc, 0, spk_y);
1054}
1055
1056static void say_to_bottom(struct vc_data *vc)
1057{
1058        say_screen_from_to(vc, spk_y, vc->vc_rows);
1059}
1060
1061static void say_from_left(struct vc_data *vc)
1062{
1063        say_line_from_to(vc, 0, spk_x, 1);
1064}
1065
1066static void say_to_right(struct vc_data *vc)
1067{
1068        say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1069}
1070
1071/* end of stub functions. */
1072
1073static void spkup_write(const char *in_buf, int count)
1074{
1075        static int rep_count;
1076        static u_char ch = '\0', old_ch = '\0';
1077        static u_short char_type, last_type;
1078        int in_count = count;
1079
1080        spk_keydown = 0;
1081        while (count--) {
1082                if (cursor_track == read_all_mode) {
1083                        /* Insert Sentence Index */
1084                        if ((in_buf == sentmarks[bn][currsentence]) &&
1085                            (currsentence <= numsentences[bn]))
1086                                synth_insert_next_index(currsentence++);
1087                }
1088                ch = (u_char)*in_buf++;
1089                char_type = spk_chartab[ch];
1090                if (ch == old_ch && !(char_type & B_NUM)) {
1091                        if (++rep_count > 2)
1092                                continue;
1093                } else {
1094                        if ((last_type & CH_RPT) && rep_count > 2) {
1095                                synth_printf(" ");
1096                                synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1097                                             ++rep_count);
1098                                synth_printf(" ");
1099                        }
1100                        rep_count = 0;
1101                }
1102                if (ch == spk_lastkey) {
1103                        rep_count = 0;
1104                        if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1105                                speak_char(ch);
1106                } else if (char_type & B_ALPHA) {
1107                        if ((synth_flags & SF_DEC) && (last_type & PUNC))
1108                                synth_buffer_add(SPACE);
1109                        synth_printf("%c", ch);
1110                } else if (char_type & B_NUM) {
1111                        rep_count = 0;
1112                        synth_printf("%c", ch);
1113                } else if (char_type & spk_punc_mask) {
1114                        speak_char(ch);
1115                        char_type &= ~PUNC;     /* for dec nospell processing */
1116                } else if (char_type & SYNTH_OK) {
1117                        /* these are usually puncts like . and , which synth
1118                         * needs for expression.
1119                         * suppress multiple to get rid of long pauses and
1120                         * clear repeat count
1121                         * so if someone has
1122                         * repeats on you don't get nothing repeated count
1123                         */
1124                        if (ch != old_ch)
1125                                synth_printf("%c", ch);
1126                        else
1127                                rep_count = 0;
1128                } else {
1129/* send space and record position, if next is num overwrite space */
1130                        if (old_ch != ch)
1131                                synth_buffer_add(SPACE);
1132                        else
1133                                rep_count = 0;
1134                }
1135                old_ch = ch;
1136                last_type = char_type;
1137        }
1138        spk_lastkey = 0;
1139        if (in_count > 2 && rep_count > 2) {
1140                if (last_type & CH_RPT) {
1141                        synth_printf(" ");
1142                        synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1143                                        ++rep_count);
1144                        synth_printf(" ");
1145                }
1146                rep_count = 0;
1147        }
1148}
1149
1150static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1151
1152static void read_all_doc(struct vc_data *vc);
1153static void cursor_done(u_long data);
1154static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1155
1156static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1157{
1158        unsigned long flags;
1159
1160        if (synth == NULL || up_flag || spk_killed)
1161                return;
1162        spin_lock_irqsave(&speakup_info.spinlock, flags);
1163        if (cursor_track == read_all_mode) {
1164                switch (value) {
1165                case KVAL(K_SHIFT):
1166                        del_timer(&cursor_timer);
1167                        spk_shut_up &= 0xfe;
1168                        spk_do_flush();
1169                        read_all_doc(vc);
1170                        break;
1171                case KVAL(K_CTRL):
1172                        del_timer(&cursor_timer);
1173                        cursor_track = prev_cursor_track;
1174                        spk_shut_up &= 0xfe;
1175                        spk_do_flush();
1176                        break;
1177                }
1178        } else {
1179                spk_shut_up &= 0xfe;
1180                spk_do_flush();
1181        }
1182        if (spk_say_ctrl && value < NUM_CTL_LABELS)
1183                synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1184        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1185}
1186
1187static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1188{
1189        unsigned long flags;
1190
1191        spin_lock_irqsave(&speakup_info.spinlock, flags);
1192        if (up_flag) {
1193                spk_lastkey = 0;
1194                spk_keydown = 0;
1195                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1196                return;
1197        }
1198        if (synth == NULL || spk_killed) {
1199                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1200                return;
1201        }
1202        spk_shut_up &= 0xfe;
1203        spk_lastkey = value;
1204        spk_keydown++;
1205        spk_parked &= 0xfe;
1206        if (spk_key_echo == 2 && value >= MINECHOCHAR)
1207                speak_char(value);
1208        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1209}
1210
1211int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1212{
1213        int i = 0, states, key_data_len;
1214        const u_char *cp = key_info;
1215        u_char *cp1 = k_buffer;
1216        u_char ch, version, num_keys;
1217
1218        version = *cp++;
1219        if (version != KEY_MAP_VER)
1220                return -1;
1221        num_keys = *cp;
1222        states = (int)cp[1];
1223        key_data_len = (states + 1) * (num_keys + 1);
1224        if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1225                return -2;
1226        memset(k_buffer, 0, SHIFT_TBL_SIZE);
1227        memset(spk_our_keys, 0, sizeof(spk_our_keys));
1228        spk_shift_table = k_buffer;
1229        spk_our_keys[0] = spk_shift_table;
1230        cp1 += SHIFT_TBL_SIZE;
1231        memcpy(cp1, cp, key_data_len + 3);
1232        /* get num_keys, states and data */
1233        cp1 += 2;               /* now pointing at shift states */
1234        for (i = 1; i <= states; i++) {
1235                ch = *cp1++;
1236                if (ch >= SHIFT_TBL_SIZE)
1237                        return -3;
1238                spk_shift_table[ch] = i;
1239        }
1240        keymap_flags = *cp1++;
1241        while ((ch = *cp1)) {
1242                if (ch >= MAX_KEY)
1243                        return -4;
1244                spk_our_keys[ch] = cp1;
1245                cp1 += states + 1;
1246        }
1247        return 0;
1248}
1249
1250static struct var_t spk_vars[] = {
1251        /* bell must be first to set high limit */
1252        {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1253        {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1254        {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1255        {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1256        {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1257        {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1258        {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1259        {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1260        {SAY_CONTROL, TOGGLE_0},
1261        {SAY_WORD_CTL, TOGGLE_0},
1262        {NO_INTERRUPT, TOGGLE_0},
1263        {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1264        V_LAST_VAR
1265};
1266
1267static void toggle_cursoring(struct vc_data *vc)
1268{
1269        if (cursor_track == read_all_mode)
1270                cursor_track = prev_cursor_track;
1271        if (++cursor_track >= CT_Max)
1272                cursor_track = 0;
1273        synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1274}
1275
1276void spk_reset_default_chars(void)
1277{
1278        int i;
1279
1280        /* First, free any non-default */
1281        for (i = 0; i < 256; i++) {
1282                if ((spk_characters[i] != NULL)
1283                    && (spk_characters[i] != spk_default_chars[i]))
1284                        kfree(spk_characters[i]);
1285        }
1286
1287        memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1288}
1289
1290void spk_reset_default_chartab(void)
1291{
1292        memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1293}
1294
1295static const struct st_bits_data *pb_edit;
1296
1297static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1298{
1299        short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1300
1301        if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1302                return -1;
1303        if (ch == SPACE) {
1304                synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1305                spk_special_handler = NULL;
1306                return 1;
1307        }
1308        if (mask < PUNC && !(ch_type & PUNC))
1309                return -1;
1310        spk_chartab[ch] ^= mask;
1311        speak_char(ch);
1312        synth_printf(" %s\n",
1313                     (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1314                     spk_msg_get(MSG_OFF));
1315        return 1;
1316}
1317
1318/* Allocation concurrency is protected by the console semaphore */
1319static int speakup_allocate(struct vc_data *vc)
1320{
1321        int vc_num;
1322
1323        vc_num = vc->vc_num;
1324        if (speakup_console[vc_num] == NULL) {
1325                speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1326                                                  GFP_ATOMIC);
1327                if (speakup_console[vc_num] == NULL)
1328                        return -ENOMEM;
1329                speakup_date(vc);
1330        } else if (!spk_parked)
1331                speakup_date(vc);
1332
1333        return 0;
1334}
1335
1336static void speakup_deallocate(struct vc_data *vc)
1337{
1338        int vc_num;
1339
1340        vc_num = vc->vc_num;
1341        kfree(speakup_console[vc_num]);
1342        speakup_console[vc_num] = NULL;
1343}
1344
1345static u_char is_cursor;
1346static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1347static int cursor_con;
1348
1349static void reset_highlight_buffers(struct vc_data *);
1350
1351static int read_all_key;
1352
1353static void start_read_all_timer(struct vc_data *vc, int command);
1354
1355enum {
1356        RA_NOTHING,
1357        RA_NEXT_SENT,
1358        RA_PREV_LINE,
1359        RA_NEXT_LINE,
1360        RA_PREV_SENT,
1361        RA_DOWN_ARROW,
1362        RA_TIMER,
1363        RA_FIND_NEXT_SENT,
1364        RA_FIND_PREV_SENT,
1365};
1366
1367static void kbd_fakekey2(struct vc_data *vc, int command)
1368{
1369        del_timer(&cursor_timer);
1370        speakup_fake_down_arrow();
1371        start_read_all_timer(vc, command);
1372}
1373
1374static void read_all_doc(struct vc_data *vc)
1375{
1376        if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1377                return;
1378        if (!synth_supports_indexing())
1379                return;
1380        if (cursor_track != read_all_mode)
1381                prev_cursor_track = cursor_track;
1382        cursor_track = read_all_mode;
1383        spk_reset_index_count(0);
1384        if (get_sentence_buf(vc, 0) == -1)
1385                kbd_fakekey2(vc, RA_DOWN_ARROW);
1386        else {
1387                say_sentence_num(0, 0);
1388                synth_insert_next_index(0);
1389                start_read_all_timer(vc, RA_TIMER);
1390        }
1391}
1392
1393static void stop_read_all(struct vc_data *vc)
1394{
1395        del_timer(&cursor_timer);
1396        cursor_track = prev_cursor_track;
1397        spk_shut_up &= 0xfe;
1398        spk_do_flush();
1399}
1400
1401static void start_read_all_timer(struct vc_data *vc, int command)
1402{
1403        struct var_t *cursor_timeout;
1404
1405        cursor_con = vc->vc_num;
1406        read_all_key = command;
1407        cursor_timeout = spk_get_var(CURSOR_TIME);
1408        mod_timer(&cursor_timer,
1409                  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1410}
1411
1412static void handle_cursor_read_all(struct vc_data *vc, int command)
1413{
1414        int indcount, sentcount, rv, sn;
1415
1416        switch (command) {
1417        case RA_NEXT_SENT:
1418                /* Get Current Sentence */
1419                spk_get_index_count(&indcount, &sentcount);
1420                /*printk("%d %d  ", indcount, sentcount); */
1421                spk_reset_index_count(sentcount + 1);
1422                if (indcount == 1) {
1423                        if (!say_sentence_num(sentcount + 1, 0)) {
1424                                kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1425                                return;
1426                        }
1427                        synth_insert_next_index(0);
1428                } else {
1429                        sn = 0;
1430                        if (!say_sentence_num(sentcount + 1, 1)) {
1431                                sn = 1;
1432                                spk_reset_index_count(sn);
1433                        } else
1434                                synth_insert_next_index(0);
1435                        if (!say_sentence_num(sn, 0)) {
1436                                kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1437                                return;
1438                        }
1439                        synth_insert_next_index(0);
1440                }
1441                start_read_all_timer(vc, RA_TIMER);
1442                break;
1443        case RA_PREV_SENT:
1444                break;
1445        case RA_NEXT_LINE:
1446                read_all_doc(vc);
1447                break;
1448        case RA_PREV_LINE:
1449                break;
1450        case RA_DOWN_ARROW:
1451                if (get_sentence_buf(vc, 0) == -1) {
1452                        kbd_fakekey2(vc, RA_DOWN_ARROW);
1453                } else {
1454                        say_sentence_num(0, 0);
1455                        synth_insert_next_index(0);
1456                        start_read_all_timer(vc, RA_TIMER);
1457                }
1458                break;
1459        case RA_FIND_NEXT_SENT:
1460                rv = get_sentence_buf(vc, 0);
1461                if (rv == -1)
1462                        read_all_doc(vc);
1463                if (rv == 0)
1464                        kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1465                else {
1466                        say_sentence_num(1, 0);
1467                        synth_insert_next_index(0);
1468                        start_read_all_timer(vc, RA_TIMER);
1469                }
1470                break;
1471        case RA_FIND_PREV_SENT:
1472                break;
1473        case RA_TIMER:
1474                spk_get_index_count(&indcount, &sentcount);
1475                if (indcount < 2)
1476                        kbd_fakekey2(vc, RA_DOWN_ARROW);
1477                else
1478                        start_read_all_timer(vc, RA_TIMER);
1479                break;
1480        }
1481}
1482
1483static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1484{
1485        unsigned long flags;
1486
1487        spin_lock_irqsave(&speakup_info.spinlock, flags);
1488        if (cursor_track == read_all_mode) {
1489                spk_parked &= 0xfe;
1490                if (synth == NULL || up_flag || spk_shut_up) {
1491                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1492                        return NOTIFY_STOP;
1493                }
1494                del_timer(&cursor_timer);
1495                spk_shut_up &= 0xfe;
1496                spk_do_flush();
1497                start_read_all_timer(vc, value + 1);
1498                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1499                return NOTIFY_STOP;
1500        }
1501        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1502        return NOTIFY_OK;
1503}
1504
1505static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1506{
1507        unsigned long flags;
1508        struct var_t *cursor_timeout;
1509
1510        spin_lock_irqsave(&speakup_info.spinlock, flags);
1511        spk_parked &= 0xfe;
1512        if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1513                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1514                return;
1515        }
1516        spk_shut_up &= 0xfe;
1517        if (spk_no_intr)
1518                spk_do_flush();
1519/* the key press flushes if !no_inter but we want to flush on cursor
1520 * moves regardless of no_inter state
1521 */
1522        is_cursor = value + 1;
1523        old_cursor_pos = vc->vc_pos;
1524        old_cursor_x = vc->vc_x;
1525        old_cursor_y = vc->vc_y;
1526        speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1527        cursor_con = vc->vc_num;
1528        if (cursor_track == CT_Highlight)
1529                reset_highlight_buffers(vc);
1530        cursor_timeout = spk_get_var(CURSOR_TIME);
1531        mod_timer(&cursor_timer,
1532                  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1533        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1534}
1535
1536static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1537{
1538        int i, bi, hi;
1539        int vc_num = vc->vc_num;
1540
1541        bi = (vc->vc_attr & 0x70) >> 4;
1542        hi = speakup_console[vc_num]->ht.highsize[bi];
1543
1544        i = 0;
1545        if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1546                speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1547                speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1548                speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1549        }
1550        while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1551                if ((ic[i] > 32) && (ic[i] < 127)) {
1552                        speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1553                        hi++;
1554                } else if ((ic[i] == 32) && (hi != 0)) {
1555                        if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1556                            32) {
1557                                speakup_console[vc_num]->ht.highbuf[bi][hi] =
1558                                    ic[i];
1559                                hi++;
1560                        }
1561                }
1562                i++;
1563        }
1564        speakup_console[vc_num]->ht.highsize[bi] = hi;
1565}
1566
1567static void reset_highlight_buffers(struct vc_data *vc)
1568{
1569        int i;
1570        int vc_num = vc->vc_num;
1571
1572        for (i = 0; i < 8; i++)
1573                speakup_console[vc_num]->ht.highsize[i] = 0;
1574}
1575
1576static int count_highlight_color(struct vc_data *vc)
1577{
1578        int i, bg;
1579        int cc;
1580        int vc_num = vc->vc_num;
1581        u16 ch;
1582        u16 *start = (u16 *)vc->vc_origin;
1583
1584        for (i = 0; i < 8; i++)
1585                speakup_console[vc_num]->ht.bgcount[i] = 0;
1586
1587        for (i = 0; i < vc->vc_rows; i++) {
1588                u16 *end = start + vc->vc_cols * 2;
1589                u16 *ptr;
1590
1591                for (ptr = start; ptr < end; ptr++) {
1592                        ch = get_attributes(vc, ptr);
1593                        bg = (ch & 0x70) >> 4;
1594                        speakup_console[vc_num]->ht.bgcount[bg]++;
1595                }
1596                start += vc->vc_size_row;
1597        }
1598
1599        cc = 0;
1600        for (i = 0; i < 8; i++)
1601                if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1602                        cc++;
1603        return cc;
1604}
1605
1606static int get_highlight_color(struct vc_data *vc)
1607{
1608        int i, j;
1609        unsigned int cptr[8];
1610        int vc_num = vc->vc_num;
1611
1612        for (i = 0; i < 8; i++)
1613                cptr[i] = i;
1614
1615        for (i = 0; i < 7; i++)
1616                for (j = i + 1; j < 8; j++)
1617                        if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1618                            speakup_console[vc_num]->ht.bgcount[cptr[j]])
1619                                swap(cptr[i], cptr[j]);
1620
1621        for (i = 0; i < 8; i++)
1622                if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1623                        if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1624                                return cptr[i];
1625        return -1;
1626}
1627
1628static int speak_highlight(struct vc_data *vc)
1629{
1630        int hc, d;
1631        int vc_num = vc->vc_num;
1632
1633        if (count_highlight_color(vc) == 1)
1634                return 0;
1635        hc = get_highlight_color(vc);
1636        if (hc != -1) {
1637                d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1638                if ((d == 1) || (d == -1))
1639                        if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1640                                return 0;
1641                spk_parked |= 0x01;
1642                spk_do_flush();
1643                spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1644                            speakup_console[vc_num]->ht.highsize[hc]);
1645                spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1646                spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1647                spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1648                return 1;
1649        }
1650        return 0;
1651}
1652
1653static void cursor_done(u_long data)
1654{
1655        struct vc_data *vc = vc_cons[cursor_con].d;
1656        unsigned long flags;
1657
1658        del_timer(&cursor_timer);
1659        spin_lock_irqsave(&speakup_info.spinlock, flags);
1660        if (cursor_con != fg_console) {
1661                is_cursor = 0;
1662                goto out;
1663        }
1664        speakup_date(vc);
1665        if (win_enabled) {
1666                if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1667                    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1668                        spk_keydown = 0;
1669                        is_cursor = 0;
1670                        goto out;
1671                }
1672        }
1673        if (cursor_track == read_all_mode) {
1674                handle_cursor_read_all(vc, read_all_key);
1675                goto out;
1676        }
1677        if (cursor_track == CT_Highlight) {
1678                if (speak_highlight(vc)) {
1679                        spk_keydown = 0;
1680                        is_cursor = 0;
1681                        goto out;
1682                }
1683        }
1684        if (cursor_track == CT_Window)
1685                speakup_win_say(vc);
1686        else if (is_cursor == 1 || is_cursor == 4)
1687                say_line_from_to(vc, 0, vc->vc_cols, 0);
1688        else
1689                say_char(vc);
1690        spk_keydown = 0;
1691        is_cursor = 0;
1692out:
1693        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1694}
1695
1696/* called by: vt_notifier_call() */
1697static void speakup_bs(struct vc_data *vc)
1698{
1699        unsigned long flags;
1700
1701        if (!speakup_console[vc->vc_num])
1702                return;
1703        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1704                /* Speakup output, discard */
1705                return;
1706        if (!spk_parked)
1707                speakup_date(vc);
1708        if (spk_shut_up || synth == NULL) {
1709                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1710                return;
1711        }
1712        if (vc->vc_num == fg_console && spk_keydown) {
1713                spk_keydown = 0;
1714                if (!is_cursor)
1715                        say_char(vc);
1716        }
1717        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1718}
1719
1720/* called by: vt_notifier_call() */
1721static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1722{
1723        unsigned long flags;
1724
1725        if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1726                return;
1727        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1728                /* Speakup output, discard */
1729                return;
1730        if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1731                bleep(3);
1732        if ((is_cursor) || (cursor_track == read_all_mode)) {
1733                if (cursor_track == CT_Highlight)
1734                        update_color_buffer(vc, str, len);
1735                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1736                return;
1737        }
1738        if (win_enabled) {
1739                if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1740                    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1741                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1742                        return;
1743                }
1744        }
1745
1746        spkup_write(str, len);
1747        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1748}
1749
1750static void speakup_con_update(struct vc_data *vc)
1751{
1752        unsigned long flags;
1753
1754        if (speakup_console[vc->vc_num] == NULL || spk_parked)
1755                return;
1756        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1757                /* Speakup output, discard */
1758                return;
1759        speakup_date(vc);
1760        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1761}
1762
1763static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1764{
1765        unsigned long flags;
1766        int on_off = 2;
1767        char *label;
1768
1769        if (synth == NULL || up_flag || spk_killed)
1770                return;
1771        spin_lock_irqsave(&speakup_info.spinlock, flags);
1772        spk_shut_up &= 0xfe;
1773        if (spk_no_intr)
1774                spk_do_flush();
1775        switch (value) {
1776        case KVAL(K_CAPS):
1777                label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1778                on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1779                break;
1780        case KVAL(K_NUM):
1781                label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1782                on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1783                break;
1784        case KVAL(K_HOLD):
1785                label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1786                on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1787                if (speakup_console[vc->vc_num])
1788                        speakup_console[vc->vc_num]->tty_stopped = on_off;
1789                break;
1790        default:
1791                spk_parked &= 0xfe;
1792                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1793                return;
1794        }
1795        if (on_off < 2)
1796                synth_printf("%s %s\n",
1797                             label, spk_msg_get(MSG_STATUS_START + on_off));
1798        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1799}
1800
1801static int inc_dec_var(u_char value)
1802{
1803        struct st_var_header *p_header;
1804        struct var_t *var_data;
1805        char num_buf[32];
1806        char *cp = num_buf;
1807        char *pn;
1808        int var_id = (int)value - VAR_START;
1809        int how = (var_id & 1) ? E_INC : E_DEC;
1810
1811        var_id = var_id / 2 + FIRST_SET_VAR;
1812        p_header = spk_get_var_header(var_id);
1813        if (p_header == NULL)
1814                return -1;
1815        if (p_header->var_type != VAR_NUM)
1816                return -1;
1817        var_data = p_header->data;
1818        if (spk_set_num_var(1, p_header, how) != 0)
1819                return -1;
1820        if (!spk_close_press) {
1821                for (pn = p_header->name; *pn; pn++) {
1822                        if (*pn == '_')
1823                                *cp = SPACE;
1824                        else
1825                                *cp++ = *pn;
1826                }
1827        }
1828        snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1829                 var_data->u.n.value);
1830        synth_printf("%s", num_buf);
1831        return 0;
1832}
1833
1834static void speakup_win_set(struct vc_data *vc)
1835{
1836        char info[40];
1837
1838        if (win_start > 1) {
1839                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1840                return;
1841        }
1842        if (spk_x < win_left || spk_y < win_top) {
1843                synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1844                return;
1845        }
1846        if (win_start && spk_x == win_left && spk_y == win_top) {
1847                win_left = 0;
1848                win_right = vc->vc_cols - 1;
1849                win_bottom = spk_y;
1850                snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1851                         (int)win_top + 1);
1852        } else {
1853                if (!win_start) {
1854                        win_top = spk_y;
1855                        win_left = spk_x;
1856                } else {
1857                        win_bottom = spk_y;
1858                        win_right = spk_x;
1859                }
1860                snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1861                         (win_start) ?
1862                                spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1863                         (int)spk_y + 1, (int)spk_x + 1);
1864        }
1865        synth_printf("%s\n", info);
1866        win_start++;
1867}
1868
1869static void speakup_win_clear(struct vc_data *vc)
1870{
1871        win_top = 0;
1872        win_bottom = 0;
1873        win_left = 0;
1874        win_right = 0;
1875        win_start = 0;
1876        synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1877}
1878
1879static void speakup_win_enable(struct vc_data *vc)
1880{
1881        if (win_start < 2) {
1882                synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1883                return;
1884        }
1885        win_enabled ^= 1;
1886        if (win_enabled)
1887                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1888        else
1889                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1890}
1891
1892static void speakup_bits(struct vc_data *vc)
1893{
1894        int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1895
1896        if (spk_special_handler != NULL || val < 1 || val > 6) {
1897                synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1898                return;
1899        }
1900        pb_edit = &spk_punc_info[val];
1901        synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1902        spk_special_handler = edit_bits;
1903}
1904
1905static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1906{
1907        static u_char goto_buf[8];
1908        static int num;
1909        int maxlen;
1910        char *cp;
1911
1912        if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1913                goto do_goto;
1914        if (type == KT_LATIN && ch == '\n')
1915                goto do_goto;
1916        if (type != 0)
1917                goto oops;
1918        if (ch == 8) {
1919                if (num == 0)
1920                        return -1;
1921                ch = goto_buf[--num];
1922                goto_buf[num] = '\0';
1923                spkup_write(&ch, 1);
1924                return 1;
1925        }
1926        if (ch < '+' || ch > 'y')
1927                goto oops;
1928        goto_buf[num++] = ch;
1929        goto_buf[num] = '\0';
1930        spkup_write(&ch, 1);
1931        maxlen = (*goto_buf >= '0') ? 3 : 4;
1932        if ((ch == '+' || ch == '-') && num == 1)
1933                return 1;
1934        if (ch >= '0' && ch <= '9' && num < maxlen)
1935                return 1;
1936        if (num < maxlen - 1 || num > maxlen)
1937                goto oops;
1938        if (ch < 'x' || ch > 'y') {
1939oops:
1940                if (!spk_killed)
1941                        synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1942                goto_buf[num = 0] = '\0';
1943                spk_special_handler = NULL;
1944                return 1;
1945        }
1946
1947        goto_pos = simple_strtoul(goto_buf, &cp, 10);
1948
1949        if (*cp == 'x') {
1950                if (*goto_buf < '0')
1951                        goto_pos += spk_x;
1952                else if (goto_pos > 0)
1953                        goto_pos--;
1954
1955                if (goto_pos >= vc->vc_cols)
1956                        goto_pos = vc->vc_cols - 1;
1957                goto_x = 1;
1958        } else {
1959                if (*goto_buf < '0')
1960                        goto_pos += spk_y;
1961                else if (goto_pos > 0)
1962                        goto_pos--;
1963
1964                if (goto_pos >= vc->vc_rows)
1965                        goto_pos = vc->vc_rows - 1;
1966                goto_x = 0;
1967        }
1968        goto_buf[num = 0] = '\0';
1969do_goto:
1970        spk_special_handler = NULL;
1971        spk_parked |= 0x01;
1972        if (goto_x) {
1973                spk_pos -= spk_x * 2;
1974                spk_x = goto_pos;
1975                spk_pos += goto_pos * 2;
1976                say_word(vc);
1977        } else {
1978                spk_y = goto_pos;
1979                spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1980                say_line(vc);
1981        }
1982        return 1;
1983}
1984
1985static void speakup_goto(struct vc_data *vc)
1986{
1987        if (spk_special_handler != NULL) {
1988                synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1989                return;
1990        }
1991        synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1992        spk_special_handler = handle_goto;
1993}
1994
1995static void speakup_help(struct vc_data *vc)
1996{
1997        spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1998}
1999
2000static void do_nothing(struct vc_data *vc)
2001{
2002        return;                 /* flush done in do_spkup */
2003}
2004
2005static u_char key_speakup, spk_key_locked;
2006
2007static void speakup_lock(struct vc_data *vc)
2008{
2009        if (!spk_key_locked) {
2010                spk_key_locked = 16;
2011                key_speakup = 16;
2012        } else {
2013                spk_key_locked = 0;
2014                key_speakup = 0;
2015        }
2016}
2017
2018typedef void (*spkup_hand) (struct vc_data *);
2019static spkup_hand spkup_handler[] = {
2020        /* must be ordered same as defines in speakup.h */
2021        do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2022        speakup_cut, speakup_paste, say_first_char, say_last_char,
2023        say_char, say_prev_char, say_next_char,
2024        say_word, say_prev_word, say_next_word,
2025        say_line, say_prev_line, say_next_line,
2026        top_edge, bottom_edge, left_edge, right_edge,
2027        spell_word, spell_word, say_screen,
2028        say_position, say_attributes,
2029        speakup_off, speakup_parked, say_line,  /* this is for indent */
2030        say_from_top, say_to_bottom,
2031        say_from_left, say_to_right,
2032        say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2033        speakup_bits, speakup_bits, speakup_bits,
2034        speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2035        speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2036};
2037
2038static void do_spkup(struct vc_data *vc, u_char value)
2039{
2040        if (spk_killed && value != SPEECH_KILL)
2041                return;
2042        spk_keydown = 0;
2043        spk_lastkey = 0;
2044        spk_shut_up &= 0xfe;
2045        this_speakup_key = value;
2046        if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2047                spk_do_flush();
2048                (*spkup_handler[value]) (vc);
2049        } else {
2050                if (inc_dec_var(value) < 0)
2051                        bleep(9);
2052        }
2053}
2054
2055static const char *pad_chars = "0123456789+-*/\015,.?()";
2056
2057static int
2058speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2059            int up_flag)
2060{
2061        unsigned long flags;
2062        int kh;
2063        u_char *key_info;
2064        u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2065        u_char shift_info, offset;
2066        int ret = 0;
2067
2068        if (synth == NULL)
2069                return 0;
2070
2071        spin_lock_irqsave(&speakup_info.spinlock, flags);
2072        tty = vc->port.tty;
2073        if (type >= 0xf0)
2074                type -= 0xf0;
2075        if (type == KT_PAD
2076                && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2077                if (up_flag) {
2078                        spk_keydown = 0;
2079                        goto out;
2080                }
2081                value = spk_lastkey = pad_chars[value];
2082                spk_keydown++;
2083                spk_parked &= 0xfe;
2084                goto no_map;
2085        }
2086        if (keycode >= MAX_KEY)
2087                goto no_map;
2088        key_info = spk_our_keys[keycode];
2089        if (!key_info)
2090                goto no_map;
2091        /* Check valid read all mode keys */
2092        if ((cursor_track == read_all_mode) && (!up_flag)) {
2093                switch (value) {
2094                case KVAL(K_DOWN):
2095                case KVAL(K_UP):
2096                case KVAL(K_LEFT):
2097                case KVAL(K_RIGHT):
2098                case KVAL(K_PGUP):
2099                case KVAL(K_PGDN):
2100                        break;
2101                default:
2102                        stop_read_all(vc);
2103                        break;
2104                }
2105        }
2106        shift_info = (shift_state & 0x0f) + key_speakup;
2107        offset = spk_shift_table[shift_info];
2108        if (offset) {
2109                new_key = key_info[offset];
2110                if (new_key) {
2111                        ret = 1;
2112                        if (new_key == SPK_KEY) {
2113                                if (!spk_key_locked)
2114                                        key_speakup = (up_flag) ? 0 : 16;
2115                                if (up_flag || spk_killed)
2116                                        goto out;
2117                                spk_shut_up &= 0xfe;
2118                                spk_do_flush();
2119                                goto out;
2120                        }
2121                        if (up_flag)
2122                                goto out;
2123                        if (last_keycode == keycode &&
2124                            time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2125                                spk_close_press = 1;
2126                                offset = spk_shift_table[shift_info + 32];
2127                                /* double press? */
2128                                if (offset && key_info[offset])
2129                                        new_key = key_info[offset];
2130                        }
2131                        last_keycode = keycode;
2132                        last_spk_jiffy = jiffies;
2133                        type = KT_SPKUP;
2134                        value = new_key;
2135                }
2136        }
2137no_map:
2138        if (type == KT_SPKUP && spk_special_handler == NULL) {
2139                do_spkup(vc, new_key);
2140                spk_close_press = 0;
2141                ret = 1;
2142                goto out;
2143        }
2144        if (up_flag || spk_killed || type == KT_SHIFT)
2145                goto out;
2146        spk_shut_up &= 0xfe;
2147        kh = (value == KVAL(K_DOWN))
2148            || (value == KVAL(K_UP))
2149            || (value == KVAL(K_LEFT))
2150            || (value == KVAL(K_RIGHT));
2151        if ((cursor_track != read_all_mode) || !kh)
2152                if (!spk_no_intr)
2153                        spk_do_flush();
2154        if (spk_special_handler) {
2155                if (type == KT_SPEC && value == 1) {
2156                        value = '\n';
2157                        type = KT_LATIN;
2158                } else if (type == KT_LETTER)
2159                        type = KT_LATIN;
2160                else if (value == 0x7f)
2161                        value = 8;      /* make del = backspace */
2162                ret = (*spk_special_handler) (vc, type, value, keycode);
2163                spk_close_press = 0;
2164                if (ret < 0)
2165                        bleep(9);
2166                goto out;
2167        }
2168        last_keycode = 0;
2169out:
2170        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2171        return ret;
2172}
2173
2174static int keyboard_notifier_call(struct notifier_block *nb,
2175                                  unsigned long code, void *_param)
2176{
2177        struct keyboard_notifier_param *param = _param;
2178        struct vc_data *vc = param->vc;
2179        int up = !param->down;
2180        int ret = NOTIFY_OK;
2181        static int keycode;     /* to hold the current keycode */
2182
2183        if (vc->vc_mode == KD_GRAPHICS)
2184                return ret;
2185
2186        /*
2187         * First, determine whether we are handling a fake keypress on
2188         * the current processor.  If we are, then return NOTIFY_OK,
2189         * to pass the keystroke up the chain.  This prevents us from
2190         * trying to take the Speakup lock while it is held by the
2191         * processor on which the simulated keystroke was generated.
2192         * Also, the simulated keystrokes should be ignored by Speakup.
2193         */
2194
2195        if (speakup_fake_key_pressed())
2196                return ret;
2197
2198        switch (code) {
2199        case KBD_KEYCODE:
2200                /* speakup requires keycode and keysym currently */
2201                keycode = param->value;
2202                break;
2203        case KBD_UNBOUND_KEYCODE:
2204                /* not used yet */
2205                break;
2206        case KBD_UNICODE:
2207                /* not used yet */
2208                break;
2209        case KBD_KEYSYM:
2210                if (speakup_key(vc, param->shift, keycode, param->value, up))
2211                        ret = NOTIFY_STOP;
2212                else if (KTYP(param->value) == KT_CUR)
2213                        ret = pre_handle_cursor(vc, KVAL(param->value), up);
2214                break;
2215        case KBD_POST_KEYSYM:{
2216                        unsigned char type = KTYP(param->value) - 0xf0;
2217                        unsigned char val = KVAL(param->value);
2218
2219                        switch (type) {
2220                        case KT_SHIFT:
2221                                do_handle_shift(vc, val, up);
2222                                break;
2223                        case KT_LATIN:
2224                        case KT_LETTER:
2225                                do_handle_latin(vc, val, up);
2226                                break;
2227                        case KT_CUR:
2228                                do_handle_cursor(vc, val, up);
2229                                break;
2230                        case KT_SPEC:
2231                                do_handle_spec(vc, val, up);
2232                                break;
2233                        }
2234                        break;
2235                }
2236        }
2237        return ret;
2238}
2239
2240static int vt_notifier_call(struct notifier_block *nb,
2241                            unsigned long code, void *_param)
2242{
2243        struct vt_notifier_param *param = _param;
2244        struct vc_data *vc = param->vc;
2245
2246        switch (code) {
2247        case VT_ALLOCATE:
2248                if (vc->vc_mode == KD_TEXT)
2249                        speakup_allocate(vc);
2250                break;
2251        case VT_DEALLOCATE:
2252                speakup_deallocate(vc);
2253                break;
2254        case VT_WRITE:
2255                if (param->c == '\b')
2256                        speakup_bs(vc);
2257                else if (param->c < 0x100) {
2258                        char d = param->c;
2259
2260                        speakup_con_write(vc, &d, 1);
2261                }
2262                break;
2263        case VT_UPDATE:
2264                speakup_con_update(vc);
2265                break;
2266        }
2267        return NOTIFY_OK;
2268}
2269
2270/* called by: module_exit() */
2271static void __exit speakup_exit(void)
2272{
2273        int i;
2274
2275        unregister_keyboard_notifier(&keyboard_notifier_block);
2276        unregister_vt_notifier(&vt_notifier_block);
2277        speakup_unregister_devsynth();
2278        speakup_cancel_paste();
2279        del_timer_sync(&cursor_timer);
2280        kthread_stop(speakup_task);
2281        speakup_task = NULL;
2282        mutex_lock(&spk_mutex);
2283        synth_release();
2284        mutex_unlock(&spk_mutex);
2285
2286        speakup_kobj_exit();
2287
2288        for (i = 0; i < MAX_NR_CONSOLES; i++)
2289                kfree(speakup_console[i]);
2290
2291        speakup_remove_virtual_keyboard();
2292
2293        for (i = 0; i < MAXVARS; i++)
2294                speakup_unregister_var(i);
2295
2296        for (i = 0; i < 256; i++) {
2297                if (spk_characters[i] != spk_default_chars[i])
2298                        kfree(spk_characters[i]);
2299        }
2300
2301        spk_free_user_msgs();
2302}
2303
2304/* call by: module_init() */
2305static int __init speakup_init(void)
2306{
2307        int i;
2308        long err = 0;
2309        struct st_spk_t *first_console;
2310        struct vc_data *vc = vc_cons[fg_console].d;
2311        struct var_t *var;
2312
2313        /* These first few initializations cannot fail. */
2314        spk_initialize_msgs();  /* Initialize arrays for i18n. */
2315        spk_reset_default_chars();
2316        spk_reset_default_chartab();
2317        spk_strlwr(synth_name);
2318        spk_vars[0].u.n.high = vc->vc_cols;
2319        for (var = spk_vars; var->var_id != MAXVARS; var++)
2320                speakup_register_var(var);
2321        for (var = synth_time_vars;
2322             (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2323                speakup_register_var(var);
2324        for (i = 1; spk_punc_info[i].mask != 0; i++)
2325                spk_set_mask_bits(NULL, i, 2);
2326
2327        spk_set_key_info(spk_key_defaults, spk_key_buf);
2328
2329        /* From here on out, initializations can fail. */
2330        err = speakup_add_virtual_keyboard();
2331        if (err)
2332                goto error_virtkeyboard;
2333
2334        first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2335        if (!first_console) {
2336                err = -ENOMEM;
2337                goto error_alloc;
2338        }
2339
2340        speakup_console[vc->vc_num] = first_console;
2341        speakup_date(vc);
2342
2343        for (i = 0; i < MAX_NR_CONSOLES; i++)
2344                if (vc_cons[i].d) {
2345                        err = speakup_allocate(vc_cons[i].d);
2346                        if (err)
2347                                goto error_kobjects;
2348                }
2349
2350        if (spk_quiet_boot)
2351                spk_shut_up |= 0x01;
2352
2353        err = speakup_kobj_init();
2354        if (err)
2355                goto error_kobjects;
2356
2357        synth_init(synth_name);
2358        speakup_register_devsynth();
2359        /*
2360         * register_devsynth might fail, but this error is not fatal.
2361         * /dev/synth is an extra feature; the rest of Speakup
2362         * will work fine without it.
2363         */
2364
2365        err = register_keyboard_notifier(&keyboard_notifier_block);
2366        if (err)
2367                goto error_kbdnotifier;
2368        err = register_vt_notifier(&vt_notifier_block);
2369        if (err)
2370                goto error_vtnotifier;
2371
2372        speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2373
2374        if (IS_ERR(speakup_task)) {
2375                err = PTR_ERR(speakup_task);
2376                goto error_task;
2377        }
2378
2379        set_user_nice(speakup_task, 10);
2380        wake_up_process(speakup_task);
2381
2382        pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2383        pr_info("synth name on entry is: %s\n", synth_name);
2384        goto out;
2385
2386error_task:
2387        unregister_vt_notifier(&vt_notifier_block);
2388
2389error_vtnotifier:
2390        unregister_keyboard_notifier(&keyboard_notifier_block);
2391        del_timer(&cursor_timer);
2392
2393error_kbdnotifier:
2394        speakup_unregister_devsynth();
2395        mutex_lock(&spk_mutex);
2396        synth_release();
2397        mutex_unlock(&spk_mutex);
2398        speakup_kobj_exit();
2399
2400error_kobjects:
2401        for (i = 0; i < MAX_NR_CONSOLES; i++)
2402                kfree(speakup_console[i]);
2403
2404error_alloc:
2405        speakup_remove_virtual_keyboard();
2406
2407error_virtkeyboard:
2408        for (i = 0; i < MAXVARS; i++)
2409                speakup_unregister_var(i);
2410
2411        for (i = 0; i < 256; i++) {
2412                if (spk_characters[i] != spk_default_chars[i])
2413                        kfree(spk_characters[i]);
2414        }
2415
2416        spk_free_user_msgs();
2417
2418out:
2419        return err;
2420}
2421
2422module_init(speakup_init);
2423module_exit(speakup_exit);
2424