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, S_IRUGO);
  62module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
  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 (u_char) (scr_readw(pos) >> 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                        c |= 0x100;
 478
 479                ch = inverse_translate(vc, c, 0);
 480                *attribs = (w & 0xff00) >> 8;
 481        }
 482        return ch;
 483}
 484
 485static void say_char(struct vc_data *vc)
 486{
 487        u_short ch;
 488
 489        spk_old_attr = spk_attr;
 490        ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
 491        if (spk_attr != spk_old_attr) {
 492                if (spk_attrib_bleep & 1)
 493                        bleep(spk_y);
 494                if (spk_attrib_bleep & 2)
 495                        say_attributes(vc);
 496        }
 497        speak_char(ch & 0xff);
 498}
 499
 500static void say_phonetic_char(struct vc_data *vc)
 501{
 502        u_short ch;
 503
 504        spk_old_attr = spk_attr;
 505        ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
 506        if (isascii(ch) && isalpha(ch)) {
 507                ch &= 0x1f;
 508                synth_printf("%s\n", phonetic[--ch]);
 509        } else {
 510                if (IS_CHAR(ch, B_NUM))
 511                        synth_printf("%s ", spk_msg_get(MSG_NUMBER));
 512                speak_char(ch);
 513        }
 514}
 515
 516static void say_prev_char(struct vc_data *vc)
 517{
 518        spk_parked |= 0x01;
 519        if (spk_x == 0) {
 520                announce_edge(vc, edge_left);
 521                return;
 522        }
 523        spk_x--;
 524        spk_pos -= 2;
 525        say_char(vc);
 526}
 527
 528static void say_next_char(struct vc_data *vc)
 529{
 530        spk_parked |= 0x01;
 531        if (spk_x == vc->vc_cols - 1) {
 532                announce_edge(vc, edge_right);
 533                return;
 534        }
 535        spk_x++;
 536        spk_pos += 2;
 537        say_char(vc);
 538}
 539
 540/* get_word - will first check to see if the character under the
 541 * reading cursor is a space and if spk_say_word_ctl is true it will
 542 * return the word space.  If spk_say_word_ctl is not set it will check to
 543 * see if there is a word starting on the next position to the right
 544 * and return that word if it exists.  If it does not exist it will
 545 * move left to the beginning of any previous word on the line or the
 546 * beginning off the line whichever comes first..
 547 */
 548
 549static u_long get_word(struct vc_data *vc)
 550{
 551        u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
 552        char ch;
 553        u_short attr_ch;
 554        u_char temp;
 555
 556        spk_old_attr = spk_attr;
 557        ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
 558
 559/* decided to take out the sayword if on a space (mis-information */
 560        if (spk_say_word_ctl && ch == SPACE) {
 561                *buf = '\0';
 562                synth_printf("%s\n", spk_msg_get(MSG_SPACE));
 563                return 0;
 564        } else if ((tmpx < vc->vc_cols - 2)
 565                   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
 566                   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
 567                       SPACE)) {
 568                tmp_pos += 2;
 569                tmpx++;
 570        } else
 571                while (tmpx > 0) {
 572                        ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
 573                        if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
 574                            && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
 575                                SPACE))
 576                                break;
 577                        tmp_pos -= 2;
 578                        tmpx--;
 579                }
 580        attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
 581        buf[cnt++] = attr_ch & 0xff;
 582        while (tmpx < vc->vc_cols - 1) {
 583                tmp_pos += 2;
 584                tmpx++;
 585                ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
 586                if ((ch == SPACE) || ch == 0
 587                    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
 588                        break;
 589                buf[cnt++] = ch;
 590        }
 591        buf[cnt] = '\0';
 592        return cnt;
 593}
 594
 595static void say_word(struct vc_data *vc)
 596{
 597        u_long cnt = get_word(vc);
 598        u_short saved_punc_mask = spk_punc_mask;
 599
 600        if (cnt == 0)
 601                return;
 602        spk_punc_mask = PUNC;
 603        buf[cnt++] = SPACE;
 604        spkup_write(buf, cnt);
 605        spk_punc_mask = saved_punc_mask;
 606}
 607
 608static void say_prev_word(struct vc_data *vc)
 609{
 610        u_char temp;
 611        char ch;
 612        u_short edge_said = 0, last_state = 0, state = 0;
 613
 614        spk_parked |= 0x01;
 615
 616        if (spk_x == 0) {
 617                if (spk_y == 0) {
 618                        announce_edge(vc, edge_top);
 619                        return;
 620                }
 621                spk_y--;
 622                spk_x = vc->vc_cols;
 623                edge_said = edge_quiet;
 624        }
 625        while (1) {
 626                if (spk_x == 0) {
 627                        if (spk_y == 0) {
 628                                edge_said = edge_top;
 629                                break;
 630                        }
 631                        if (edge_said != edge_quiet)
 632                                edge_said = edge_left;
 633                        if (state > 0)
 634                                break;
 635                        spk_y--;
 636                        spk_x = vc->vc_cols - 1;
 637                } else
 638                        spk_x--;
 639                spk_pos -= 2;
 640                ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
 641                if (ch == SPACE || ch == 0)
 642                        state = 0;
 643                else if (IS_WDLM(ch))
 644                        state = 1;
 645                else
 646                        state = 2;
 647                if (state < last_state) {
 648                        spk_pos += 2;
 649                        spk_x++;
 650                        break;
 651                }
 652                last_state = state;
 653        }
 654        if (spk_x == 0 && edge_said == edge_quiet)
 655                edge_said = edge_left;
 656        if (edge_said > 0 && edge_said < edge_quiet)
 657                announce_edge(vc, edge_said);
 658        say_word(vc);
 659}
 660
 661static void say_next_word(struct vc_data *vc)
 662{
 663        u_char temp;
 664        char ch;
 665        u_short edge_said = 0, last_state = 2, state = 0;
 666
 667        spk_parked |= 0x01;
 668        if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
 669                announce_edge(vc, edge_bottom);
 670                return;
 671        }
 672        while (1) {
 673                ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
 674                if (ch == SPACE || ch == 0)
 675                        state = 0;
 676                else if (IS_WDLM(ch))
 677                        state = 1;
 678                else
 679                        state = 2;
 680                if (state > last_state)
 681                        break;
 682                if (spk_x >= vc->vc_cols - 1) {
 683                        if (spk_y == vc->vc_rows - 1) {
 684                                edge_said = edge_bottom;
 685                                break;
 686                        }
 687                        state = 0;
 688                        spk_y++;
 689                        spk_x = 0;
 690                        edge_said = edge_right;
 691                } else
 692                        spk_x++;
 693                spk_pos += 2;
 694                last_state = state;
 695        }
 696        if (edge_said > 0)
 697                announce_edge(vc, edge_said);
 698        say_word(vc);
 699}
 700
 701static void spell_word(struct vc_data *vc)
 702{
 703        static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
 704        char *cp = buf, *str_cap = spk_str_caps_stop;
 705        char *cp1, *last_cap = spk_str_caps_stop;
 706        u_char ch;
 707
 708        if (!get_word(vc))
 709                return;
 710        while ((ch = (u_char) *cp)) {
 711                if (cp != buf)
 712                        synth_printf(" %s ", delay_str[spk_spell_delay]);
 713                if (IS_CHAR(ch, B_CAP)) {
 714                        str_cap = spk_str_caps_start;
 715                        if (*spk_str_caps_stop)
 716                                spk_pitch_shift++;
 717                        else    /* synth has no pitch */
 718                                last_cap = spk_str_caps_stop;
 719                } else
 720                        str_cap = spk_str_caps_stop;
 721                if (str_cap != last_cap) {
 722                        synth_printf("%s", str_cap);
 723                        last_cap = str_cap;
 724                }
 725                if (this_speakup_key == SPELL_PHONETIC
 726                    && (isascii(ch) && isalpha(ch))) {
 727                        ch &= 31;
 728                        cp1 = phonetic[--ch];
 729                } else {
 730                        cp1 = spk_characters[ch];
 731                        if (*cp1 == '^') {
 732                                synth_printf("%s", spk_msg_get(MSG_CTRL));
 733                                cp1++;
 734                        }
 735                }
 736                synth_printf("%s", cp1);
 737                cp++;
 738        }
 739        if (str_cap != spk_str_caps_stop)
 740                synth_printf("%s", spk_str_caps_stop);
 741}
 742
 743static int get_line(struct vc_data *vc)
 744{
 745        u_long tmp = spk_pos - (spk_x * 2);
 746        int i = 0;
 747        u_char tmp2;
 748
 749        spk_old_attr = spk_attr;
 750        spk_attr = get_attributes(vc, (u_short *)spk_pos);
 751        for (i = 0; i < vc->vc_cols; i++) {
 752                buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
 753                tmp += 2;
 754        }
 755        for (--i; i >= 0; i--)
 756                if (buf[i] != SPACE)
 757                        break;
 758        return ++i;
 759}
 760
 761static void say_line(struct vc_data *vc)
 762{
 763        int i = get_line(vc);
 764        char *cp;
 765        u_short saved_punc_mask = spk_punc_mask;
 766
 767        if (i == 0) {
 768                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 769                return;
 770        }
 771        buf[i++] = '\n';
 772        if (this_speakup_key == SAY_LINE_INDENT) {
 773                cp = buf;
 774                while (*cp == SPACE)
 775                        cp++;
 776                synth_printf("%d, ", (cp - buf) + 1);
 777        }
 778        spk_punc_mask = spk_punc_masks[spk_reading_punc];
 779        spkup_write(buf, i);
 780        spk_punc_mask = saved_punc_mask;
 781}
 782
 783static void say_prev_line(struct vc_data *vc)
 784{
 785        spk_parked |= 0x01;
 786        if (spk_y == 0) {
 787                announce_edge(vc, edge_top);
 788                return;
 789        }
 790        spk_y--;
 791        spk_pos -= vc->vc_size_row;
 792        say_line(vc);
 793}
 794
 795static void say_next_line(struct vc_data *vc)
 796{
 797        spk_parked |= 0x01;
 798        if (spk_y == vc->vc_rows - 1) {
 799                announce_edge(vc, edge_bottom);
 800                return;
 801        }
 802        spk_y++;
 803        spk_pos += vc->vc_size_row;
 804        say_line(vc);
 805}
 806
 807static int say_from_to(struct vc_data *vc, u_long from, u_long to,
 808                       int read_punc)
 809{
 810        int i = 0;
 811        u_char tmp;
 812        u_short saved_punc_mask = spk_punc_mask;
 813
 814        spk_old_attr = spk_attr;
 815        spk_attr = get_attributes(vc, (u_short *)from);
 816        while (from < to) {
 817                buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
 818                from += 2;
 819                if (i >= vc->vc_size_row)
 820                        break;
 821        }
 822        for (--i; i >= 0; i--)
 823                if (buf[i] != SPACE)
 824                        break;
 825        buf[++i] = SPACE;
 826        buf[++i] = '\0';
 827        if (i < 1)
 828                return i;
 829        if (read_punc)
 830                spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
 831        spkup_write(buf, i);
 832        if (read_punc)
 833                spk_punc_mask = saved_punc_mask;
 834        return i - 1;
 835}
 836
 837static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
 838                             int read_punc)
 839{
 840        u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
 841        u_long end = start + (to * 2);
 842
 843        start += from * 2;
 844        if (say_from_to(vc, start, end, read_punc) <= 0)
 845                if (cursor_track != read_all_mode)
 846                        synth_printf("%s\n", spk_msg_get(MSG_BLANK));
 847}
 848
 849/* Sentence Reading Commands */
 850
 851static int currsentence;
 852static int numsentences[2];
 853static char *sentbufend[2];
 854static char *sentmarks[2][10];
 855static int currbuf;
 856static int bn;
 857static char sentbuf[2][256];
 858
 859static int say_sentence_num(int num, int prev)
 860{
 861        bn = currbuf;
 862        currsentence = num + 1;
 863        if (prev && --bn == -1)
 864                bn = 1;
 865
 866        if (num > numsentences[bn])
 867                return 0;
 868
 869        spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
 870        return 1;
 871}
 872
 873static int get_sentence_buf(struct vc_data *vc, int read_punc)
 874{
 875        u_long start, end;
 876        int i, bn;
 877        u_char tmp;
 878
 879        currbuf++;
 880        if (currbuf == 2)
 881                currbuf = 0;
 882        bn = currbuf;
 883        start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
 884        end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
 885
 886        numsentences[bn] = 0;
 887        sentmarks[bn][0] = &sentbuf[bn][0];
 888        i = 0;
 889        spk_old_attr = spk_attr;
 890        spk_attr = get_attributes(vc, (u_short *)start);
 891
 892        while (start < end) {
 893                sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
 894                if (i > 0) {
 895                        if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
 896                            && numsentences[bn] < 9) {
 897                                /* Sentence Marker */
 898                                numsentences[bn]++;
 899                                sentmarks[bn][numsentences[bn]] =
 900                                    &sentbuf[bn][i];
 901                        }
 902                }
 903                i++;
 904                start += 2;
 905                if (i >= vc->vc_size_row)
 906                        break;
 907        }
 908
 909        for (--i; i >= 0; i--)
 910                if (sentbuf[bn][i] != SPACE)
 911                        break;
 912
 913        if (i < 1)
 914                return -1;
 915
 916        sentbuf[bn][++i] = SPACE;
 917        sentbuf[bn][++i] = '\0';
 918
 919        sentbufend[bn] = &sentbuf[bn][i];
 920        return numsentences[bn];
 921}
 922
 923static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
 924{
 925        u_long start = vc->vc_origin, end;
 926
 927        if (from > 0)
 928                start += from * vc->vc_size_row;
 929        if (to > vc->vc_rows)
 930                to = vc->vc_rows;
 931        end = vc->vc_origin + (to * vc->vc_size_row);
 932        for (from = start; from < end; from = to) {
 933                to = from + vc->vc_size_row;
 934                say_from_to(vc, from, to, 1);
 935        }
 936}
 937
 938static void say_screen(struct vc_data *vc)
 939{
 940        say_screen_from_to(vc, 0, vc->vc_rows);
 941}
 942
 943static void speakup_win_say(struct vc_data *vc)
 944{
 945        u_long start, end, from, to;
 946
 947        if (win_start < 2) {
 948                synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
 949                return;
 950        }
 951        start = vc->vc_origin + (win_top * vc->vc_size_row);
 952        end = vc->vc_origin + (win_bottom * vc->vc_size_row);
 953        while (start <= end) {
 954                from = start + (win_left * 2);
 955                to = start + (win_right * 2);
 956                say_from_to(vc, from, to, 1);
 957                start += vc->vc_size_row;
 958        }
 959}
 960
 961static void top_edge(struct vc_data *vc)
 962{
 963        spk_parked |= 0x01;
 964        spk_pos = vc->vc_origin + 2 * spk_x;
 965        spk_y = 0;
 966        say_line(vc);
 967}
 968
 969static void bottom_edge(struct vc_data *vc)
 970{
 971        spk_parked |= 0x01;
 972        spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
 973        spk_y = vc->vc_rows - 1;
 974        say_line(vc);
 975}
 976
 977static void left_edge(struct vc_data *vc)
 978{
 979        spk_parked |= 0x01;
 980        spk_pos -= spk_x * 2;
 981        spk_x = 0;
 982        say_char(vc);
 983}
 984
 985static void right_edge(struct vc_data *vc)
 986{
 987        spk_parked |= 0x01;
 988        spk_pos += (vc->vc_cols - spk_x - 1) * 2;
 989        spk_x = vc->vc_cols - 1;
 990        say_char(vc);
 991}
 992
 993static void say_first_char(struct vc_data *vc)
 994{
 995        int i, len = get_line(vc);
 996        u_char ch;
 997
 998        spk_parked |= 0x01;
 999        if (len == 0) {
1000                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1001                return;
1002        }
1003        for (i = 0; i < len; i++)
1004                if (buf[i] != SPACE)
1005                        break;
1006        ch = buf[i];
1007        spk_pos -= (spk_x - i) * 2;
1008        spk_x = i;
1009        synth_printf("%d, ", ++i);
1010        speak_char(ch);
1011}
1012
1013static void say_last_char(struct vc_data *vc)
1014{
1015        int len = get_line(vc);
1016        u_char ch;
1017
1018        spk_parked |= 0x01;
1019        if (len == 0) {
1020                synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1021                return;
1022        }
1023        ch = buf[--len];
1024        spk_pos -= (spk_x - len) * 2;
1025        spk_x = len;
1026        synth_printf("%d, ", ++len);
1027        speak_char(ch);
1028}
1029
1030static void say_position(struct vc_data *vc)
1031{
1032        synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1033                     vc->vc_num + 1);
1034        synth_printf("\n");
1035}
1036
1037/* Added by brianb */
1038static void say_char_num(struct vc_data *vc)
1039{
1040        u_char tmp;
1041        u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1042
1043        ch &= 0xff;
1044        synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1045}
1046
1047/* these are stub functions to keep keyboard.c happy. */
1048
1049static void say_from_top(struct vc_data *vc)
1050{
1051        say_screen_from_to(vc, 0, spk_y);
1052}
1053
1054static void say_to_bottom(struct vc_data *vc)
1055{
1056        say_screen_from_to(vc, spk_y, vc->vc_rows);
1057}
1058
1059static void say_from_left(struct vc_data *vc)
1060{
1061        say_line_from_to(vc, 0, spk_x, 1);
1062}
1063
1064static void say_to_right(struct vc_data *vc)
1065{
1066        say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1067}
1068
1069/* end of stub functions. */
1070
1071static void spkup_write(const char *in_buf, int count)
1072{
1073        static int rep_count;
1074        static u_char ch = '\0', old_ch = '\0';
1075        static u_short char_type, last_type;
1076        int in_count = count;
1077
1078        spk_keydown = 0;
1079        while (count--) {
1080                if (cursor_track == read_all_mode) {
1081                        /* Insert Sentence Index */
1082                        if ((in_buf == sentmarks[bn][currsentence]) &&
1083                            (currsentence <= numsentences[bn]))
1084                                synth_insert_next_index(currsentence++);
1085                }
1086                ch = (u_char) *in_buf++;
1087                char_type = spk_chartab[ch];
1088                if (ch == old_ch && !(char_type & B_NUM)) {
1089                        if (++rep_count > 2)
1090                                continue;
1091                } else {
1092                        if ((last_type & CH_RPT) && rep_count > 2) {
1093                                synth_printf(" ");
1094                                synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1095                                             ++rep_count);
1096                                synth_printf(" ");
1097                        }
1098                        rep_count = 0;
1099                }
1100                if (ch == spk_lastkey) {
1101                        rep_count = 0;
1102                        if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1103                                speak_char(ch);
1104                } else if (char_type & B_ALPHA) {
1105                        if ((synth_flags & SF_DEC) && (last_type & PUNC))
1106                                synth_buffer_add(SPACE);
1107                        synth_printf("%c", ch);
1108                } else if (char_type & B_NUM) {
1109                        rep_count = 0;
1110                        synth_printf("%c", ch);
1111                } else if (char_type & spk_punc_mask) {
1112                        speak_char(ch);
1113                        char_type &= ~PUNC;     /* for dec nospell processing */
1114                } else if (char_type & SYNTH_OK) {
1115                        /* these are usually puncts like . and , which synth
1116                         * needs for expression.
1117                         * suppress multiple to get rid of long pauses and
1118                         * clear repeat count
1119                         * so if someone has
1120                         * repeats on you don't get nothing repeated count
1121                         */
1122                        if (ch != old_ch)
1123                                synth_printf("%c", ch);
1124                        else
1125                                rep_count = 0;
1126                } else {
1127/* send space and record position, if next is num overwrite space */
1128                        if (old_ch != ch)
1129                                synth_buffer_add(SPACE);
1130                        else
1131                                rep_count = 0;
1132                }
1133                old_ch = ch;
1134                last_type = char_type;
1135        }
1136        spk_lastkey = 0;
1137        if (in_count > 2 && rep_count > 2) {
1138                if (last_type & CH_RPT) {
1139                        synth_printf(" ");
1140                        synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1141                                        ++rep_count);
1142                        synth_printf(" ");
1143                }
1144                rep_count = 0;
1145        }
1146}
1147
1148static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1149
1150static void read_all_doc(struct vc_data *vc);
1151static void cursor_done(u_long data);
1152static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1153
1154static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1155{
1156        unsigned long flags;
1157
1158        if (synth == NULL || up_flag || spk_killed)
1159                return;
1160        spin_lock_irqsave(&speakup_info.spinlock, flags);
1161        if (cursor_track == read_all_mode) {
1162                switch (value) {
1163                case KVAL(K_SHIFT):
1164                        del_timer(&cursor_timer);
1165                        spk_shut_up &= 0xfe;
1166                        spk_do_flush();
1167                        read_all_doc(vc);
1168                        break;
1169                case KVAL(K_CTRL):
1170                        del_timer(&cursor_timer);
1171                        cursor_track = prev_cursor_track;
1172                        spk_shut_up &= 0xfe;
1173                        spk_do_flush();
1174                        break;
1175                }
1176        } else {
1177                spk_shut_up &= 0xfe;
1178                spk_do_flush();
1179        }
1180        if (spk_say_ctrl && value < NUM_CTL_LABELS)
1181                synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1182        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1183}
1184
1185static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1186{
1187        unsigned long flags;
1188
1189        spin_lock_irqsave(&speakup_info.spinlock, flags);
1190        if (up_flag) {
1191                spk_lastkey = 0;
1192                spk_keydown = 0;
1193                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1194                return;
1195        }
1196        if (synth == NULL || spk_killed) {
1197                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1198                return;
1199        }
1200        spk_shut_up &= 0xfe;
1201        spk_lastkey = value;
1202        spk_keydown++;
1203        spk_parked &= 0xfe;
1204        if (spk_key_echo == 2 && value >= MINECHOCHAR)
1205                speak_char(value);
1206        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1207}
1208
1209int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1210{
1211        int i = 0, states, key_data_len;
1212        const u_char *cp = key_info;
1213        u_char *cp1 = k_buffer;
1214        u_char ch, version, num_keys;
1215
1216        version = *cp++;
1217        if (version != KEY_MAP_VER)
1218                return -1;
1219        num_keys = *cp;
1220        states = (int)cp[1];
1221        key_data_len = (states + 1) * (num_keys + 1);
1222        if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1223                return -2;
1224        memset(k_buffer, 0, SHIFT_TBL_SIZE);
1225        memset(spk_our_keys, 0, sizeof(spk_our_keys));
1226        spk_shift_table = k_buffer;
1227        spk_our_keys[0] = spk_shift_table;
1228        cp1 += SHIFT_TBL_SIZE;
1229        memcpy(cp1, cp, key_data_len + 3);
1230        /* get num_keys, states and data */
1231        cp1 += 2;               /* now pointing at shift states */
1232        for (i = 1; i <= states; i++) {
1233                ch = *cp1++;
1234                if (ch >= SHIFT_TBL_SIZE)
1235                        return -3;
1236                spk_shift_table[ch] = i;
1237        }
1238        keymap_flags = *cp1++;
1239        while ((ch = *cp1)) {
1240                if (ch >= MAX_KEY)
1241                        return -4;
1242                spk_our_keys[ch] = cp1;
1243                cp1 += states + 1;
1244        }
1245        return 0;
1246}
1247
1248static struct var_t spk_vars[] = {
1249        /* bell must be first to set high limit */
1250        {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1251        {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1252        {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1253        {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1254        {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1255        {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1256        {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1257        {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1258        {SAY_CONTROL, TOGGLE_0},
1259        {SAY_WORD_CTL, TOGGLE_0},
1260        {NO_INTERRUPT, TOGGLE_0},
1261        {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1262        V_LAST_VAR
1263};
1264
1265static void toggle_cursoring(struct vc_data *vc)
1266{
1267        if (cursor_track == read_all_mode)
1268                cursor_track = prev_cursor_track;
1269        if (++cursor_track >= CT_Max)
1270                cursor_track = 0;
1271        synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1272}
1273
1274void spk_reset_default_chars(void)
1275{
1276        int i;
1277
1278        /* First, free any non-default */
1279        for (i = 0; i < 256; i++) {
1280                if ((spk_characters[i] != NULL)
1281                    && (spk_characters[i] != spk_default_chars[i]))
1282                        kfree(spk_characters[i]);
1283        }
1284
1285        memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1286}
1287
1288void spk_reset_default_chartab(void)
1289{
1290        memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1291}
1292
1293static const struct st_bits_data *pb_edit;
1294
1295static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1296{
1297        short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1298
1299        if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1300                return -1;
1301        if (ch == SPACE) {
1302                synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1303                spk_special_handler = NULL;
1304                return 1;
1305        }
1306        if (mask < PUNC && !(ch_type & PUNC))
1307                return -1;
1308        spk_chartab[ch] ^= mask;
1309        speak_char(ch);
1310        synth_printf(" %s\n",
1311                     (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1312                     spk_msg_get(MSG_OFF));
1313        return 1;
1314}
1315
1316/* Allocation concurrency is protected by the console semaphore */
1317static int speakup_allocate(struct vc_data *vc)
1318{
1319        int vc_num;
1320
1321        vc_num = vc->vc_num;
1322        if (speakup_console[vc_num] == NULL) {
1323                speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1324                                                  GFP_ATOMIC);
1325                if (speakup_console[vc_num] == NULL)
1326                        return -ENOMEM;
1327                speakup_date(vc);
1328        } else if (!spk_parked)
1329                speakup_date(vc);
1330
1331        return 0;
1332}
1333
1334static void speakup_deallocate(struct vc_data *vc)
1335{
1336        int vc_num;
1337
1338        vc_num = vc->vc_num;
1339        kfree(speakup_console[vc_num]);
1340        speakup_console[vc_num] = NULL;
1341}
1342
1343static u_char is_cursor;
1344static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1345static int cursor_con;
1346
1347static void reset_highlight_buffers(struct vc_data *);
1348
1349static int read_all_key;
1350
1351static void start_read_all_timer(struct vc_data *vc, int command);
1352
1353enum {
1354        RA_NOTHING,
1355        RA_NEXT_SENT,
1356        RA_PREV_LINE,
1357        RA_NEXT_LINE,
1358        RA_PREV_SENT,
1359        RA_DOWN_ARROW,
1360        RA_TIMER,
1361        RA_FIND_NEXT_SENT,
1362        RA_FIND_PREV_SENT,
1363};
1364
1365static void kbd_fakekey2(struct vc_data *vc, int command)
1366{
1367        del_timer(&cursor_timer);
1368        speakup_fake_down_arrow();
1369        start_read_all_timer(vc, command);
1370}
1371
1372static void read_all_doc(struct vc_data *vc)
1373{
1374        if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1375                return;
1376        if (!synth_supports_indexing())
1377                return;
1378        if (cursor_track != read_all_mode)
1379                prev_cursor_track = cursor_track;
1380        cursor_track = read_all_mode;
1381        spk_reset_index_count(0);
1382        if (get_sentence_buf(vc, 0) == -1)
1383                kbd_fakekey2(vc, RA_DOWN_ARROW);
1384        else {
1385                say_sentence_num(0, 0);
1386                synth_insert_next_index(0);
1387                start_read_all_timer(vc, RA_TIMER);
1388        }
1389}
1390
1391static void stop_read_all(struct vc_data *vc)
1392{
1393        del_timer(&cursor_timer);
1394        cursor_track = prev_cursor_track;
1395        spk_shut_up &= 0xfe;
1396        spk_do_flush();
1397}
1398
1399static void start_read_all_timer(struct vc_data *vc, int command)
1400{
1401        struct var_t *cursor_timeout;
1402
1403        cursor_con = vc->vc_num;
1404        read_all_key = command;
1405        cursor_timeout = spk_get_var(CURSOR_TIME);
1406        mod_timer(&cursor_timer,
1407                  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1408}
1409
1410static void handle_cursor_read_all(struct vc_data *vc, int command)
1411{
1412        int indcount, sentcount, rv, sn;
1413
1414        switch (command) {
1415        case RA_NEXT_SENT:
1416                /* Get Current Sentence */
1417                spk_get_index_count(&indcount, &sentcount);
1418                /*printk("%d %d  ", indcount, sentcount); */
1419                spk_reset_index_count(sentcount + 1);
1420                if (indcount == 1) {
1421                        if (!say_sentence_num(sentcount + 1, 0)) {
1422                                kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1423                                return;
1424                        }
1425                        synth_insert_next_index(0);
1426                } else {
1427                        sn = 0;
1428                        if (!say_sentence_num(sentcount + 1, 1)) {
1429                                sn = 1;
1430                                spk_reset_index_count(sn);
1431                        } else
1432                                synth_insert_next_index(0);
1433                        if (!say_sentence_num(sn, 0)) {
1434                                kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1435                                return;
1436                        }
1437                        synth_insert_next_index(0);
1438                }
1439                start_read_all_timer(vc, RA_TIMER);
1440                break;
1441        case RA_PREV_SENT:
1442                break;
1443        case RA_NEXT_LINE:
1444                read_all_doc(vc);
1445                break;
1446        case RA_PREV_LINE:
1447                break;
1448        case RA_DOWN_ARROW:
1449                if (get_sentence_buf(vc, 0) == -1) {
1450                        kbd_fakekey2(vc, RA_DOWN_ARROW);
1451                } else {
1452                        say_sentence_num(0, 0);
1453                        synth_insert_next_index(0);
1454                        start_read_all_timer(vc, RA_TIMER);
1455                }
1456                break;
1457        case RA_FIND_NEXT_SENT:
1458                rv = get_sentence_buf(vc, 0);
1459                if (rv == -1)
1460                        read_all_doc(vc);
1461                if (rv == 0)
1462                        kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1463                else {
1464                        say_sentence_num(1, 0);
1465                        synth_insert_next_index(0);
1466                        start_read_all_timer(vc, RA_TIMER);
1467                }
1468                break;
1469        case RA_FIND_PREV_SENT:
1470                break;
1471        case RA_TIMER:
1472                spk_get_index_count(&indcount, &sentcount);
1473                if (indcount < 2)
1474                        kbd_fakekey2(vc, RA_DOWN_ARROW);
1475                else
1476                        start_read_all_timer(vc, RA_TIMER);
1477                break;
1478        }
1479}
1480
1481static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1482{
1483        unsigned long flags;
1484
1485        spin_lock_irqsave(&speakup_info.spinlock, flags);
1486        if (cursor_track == read_all_mode) {
1487                spk_parked &= 0xfe;
1488                if (synth == NULL || up_flag || spk_shut_up) {
1489                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1490                        return NOTIFY_STOP;
1491                }
1492                del_timer(&cursor_timer);
1493                spk_shut_up &= 0xfe;
1494                spk_do_flush();
1495                start_read_all_timer(vc, value + 1);
1496                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1497                return NOTIFY_STOP;
1498        }
1499        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1500        return NOTIFY_OK;
1501}
1502
1503static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1504{
1505        unsigned long flags;
1506        struct var_t *cursor_timeout;
1507
1508        spin_lock_irqsave(&speakup_info.spinlock, flags);
1509        spk_parked &= 0xfe;
1510        if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1511                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1512                return;
1513        }
1514        spk_shut_up &= 0xfe;
1515        if (spk_no_intr)
1516                spk_do_flush();
1517/* the key press flushes if !no_inter but we want to flush on cursor
1518 * moves regardless of no_inter state
1519 */
1520        is_cursor = value + 1;
1521        old_cursor_pos = vc->vc_pos;
1522        old_cursor_x = vc->vc_x;
1523        old_cursor_y = vc->vc_y;
1524        speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1525        cursor_con = vc->vc_num;
1526        if (cursor_track == CT_Highlight)
1527                reset_highlight_buffers(vc);
1528        cursor_timeout = spk_get_var(CURSOR_TIME);
1529        mod_timer(&cursor_timer,
1530                  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1531        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1532}
1533
1534static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1535{
1536        int i, bi, hi;
1537        int vc_num = vc->vc_num;
1538
1539        bi = (vc->vc_attr & 0x70) >> 4;
1540        hi = speakup_console[vc_num]->ht.highsize[bi];
1541
1542        i = 0;
1543        if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1544                speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1545                speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1546                speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1547        }
1548        while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1549                if ((ic[i] > 32) && (ic[i] < 127)) {
1550                        speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1551                        hi++;
1552                } else if ((ic[i] == 32) && (hi != 0)) {
1553                        if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1554                            32) {
1555                                speakup_console[vc_num]->ht.highbuf[bi][hi] =
1556                                    ic[i];
1557                                hi++;
1558                        }
1559                }
1560                i++;
1561        }
1562        speakup_console[vc_num]->ht.highsize[bi] = hi;
1563}
1564
1565static void reset_highlight_buffers(struct vc_data *vc)
1566{
1567        int i;
1568        int vc_num = vc->vc_num;
1569
1570        for (i = 0; i < 8; i++)
1571                speakup_console[vc_num]->ht.highsize[i] = 0;
1572}
1573
1574static int count_highlight_color(struct vc_data *vc)
1575{
1576        int i, bg;
1577        int cc;
1578        int vc_num = vc->vc_num;
1579        u16 ch;
1580        u16 *start = (u16 *) vc->vc_origin;
1581
1582        for (i = 0; i < 8; i++)
1583                speakup_console[vc_num]->ht.bgcount[i] = 0;
1584
1585        for (i = 0; i < vc->vc_rows; i++) {
1586                u16 *end = start + vc->vc_cols * 2;
1587                u16 *ptr;
1588
1589                for (ptr = start; ptr < end; ptr++) {
1590                        ch = get_attributes(vc, ptr);
1591                        bg = (ch & 0x70) >> 4;
1592                        speakup_console[vc_num]->ht.bgcount[bg]++;
1593                }
1594                start += vc->vc_size_row;
1595        }
1596
1597        cc = 0;
1598        for (i = 0; i < 8; i++)
1599                if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1600                        cc++;
1601        return cc;
1602}
1603
1604static int get_highlight_color(struct vc_data *vc)
1605{
1606        int i, j;
1607        unsigned int cptr[8];
1608        int vc_num = vc->vc_num;
1609
1610        for (i = 0; i < 8; i++)
1611                cptr[i] = i;
1612
1613        for (i = 0; i < 7; i++)
1614                for (j = i + 1; j < 8; j++)
1615                        if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1616                            speakup_console[vc_num]->ht.bgcount[cptr[j]])
1617                                swap(cptr[i], cptr[j]);
1618
1619        for (i = 0; i < 8; i++)
1620                if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1621                        if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1622                                return cptr[i];
1623        return -1;
1624}
1625
1626static int speak_highlight(struct vc_data *vc)
1627{
1628        int hc, d;
1629        int vc_num = vc->vc_num;
1630
1631        if (count_highlight_color(vc) == 1)
1632                return 0;
1633        hc = get_highlight_color(vc);
1634        if (hc != -1) {
1635                d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1636                if ((d == 1) || (d == -1))
1637                        if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1638                                return 0;
1639                spk_parked |= 0x01;
1640                spk_do_flush();
1641                spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1642                            speakup_console[vc_num]->ht.highsize[hc]);
1643                spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1644                spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1645                spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1646                return 1;
1647        }
1648        return 0;
1649}
1650
1651static void cursor_done(u_long data)
1652{
1653        struct vc_data *vc = vc_cons[cursor_con].d;
1654        unsigned long flags;
1655
1656        del_timer(&cursor_timer);
1657        spin_lock_irqsave(&speakup_info.spinlock, flags);
1658        if (cursor_con != fg_console) {
1659                is_cursor = 0;
1660                goto out;
1661        }
1662        speakup_date(vc);
1663        if (win_enabled) {
1664                if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1665                    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1666                        spk_keydown = 0;
1667                        is_cursor = 0;
1668                        goto out;
1669                }
1670        }
1671        if (cursor_track == read_all_mode) {
1672                handle_cursor_read_all(vc, read_all_key);
1673                goto out;
1674        }
1675        if (cursor_track == CT_Highlight) {
1676                if (speak_highlight(vc)) {
1677                        spk_keydown = 0;
1678                        is_cursor = 0;
1679                        goto out;
1680                }
1681        }
1682        if (cursor_track == CT_Window)
1683                speakup_win_say(vc);
1684        else if (is_cursor == 1 || is_cursor == 4)
1685                say_line_from_to(vc, 0, vc->vc_cols, 0);
1686        else
1687                say_char(vc);
1688        spk_keydown = 0;
1689        is_cursor = 0;
1690out:
1691        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1692}
1693
1694/* called by: vt_notifier_call() */
1695static void speakup_bs(struct vc_data *vc)
1696{
1697        unsigned long flags;
1698
1699        if (!speakup_console[vc->vc_num])
1700                return;
1701        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1702                /* Speakup output, discard */
1703                return;
1704        if (!spk_parked)
1705                speakup_date(vc);
1706        if (spk_shut_up || synth == NULL) {
1707                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1708                return;
1709        }
1710        if (vc->vc_num == fg_console && spk_keydown) {
1711                spk_keydown = 0;
1712                if (!is_cursor)
1713                        say_char(vc);
1714        }
1715        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1716}
1717
1718/* called by: vt_notifier_call() */
1719static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1720{
1721        unsigned long flags;
1722
1723        if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1724                return;
1725        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1726                /* Speakup output, discard */
1727                return;
1728        if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1729                bleep(3);
1730        if ((is_cursor) || (cursor_track == read_all_mode)) {
1731                if (cursor_track == CT_Highlight)
1732                        update_color_buffer(vc, str, len);
1733                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1734                return;
1735        }
1736        if (win_enabled) {
1737                if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1738                    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1739                        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1740                        return;
1741                }
1742        }
1743
1744        spkup_write(str, len);
1745        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1746}
1747
1748static void speakup_con_update(struct vc_data *vc)
1749{
1750        unsigned long flags;
1751
1752        if (speakup_console[vc->vc_num] == NULL || spk_parked)
1753                return;
1754        if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1755                /* Speakup output, discard */
1756                return;
1757        speakup_date(vc);
1758        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1759}
1760
1761static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1762{
1763        unsigned long flags;
1764        int on_off = 2;
1765        char *label;
1766
1767        if (synth == NULL || up_flag || spk_killed)
1768                return;
1769        spin_lock_irqsave(&speakup_info.spinlock, flags);
1770        spk_shut_up &= 0xfe;
1771        if (spk_no_intr)
1772                spk_do_flush();
1773        switch (value) {
1774        case KVAL(K_CAPS):
1775                label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1776                on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1777                break;
1778        case KVAL(K_NUM):
1779                label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1780                on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1781                break;
1782        case KVAL(K_HOLD):
1783                label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1784                on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1785                if (speakup_console[vc->vc_num])
1786                        speakup_console[vc->vc_num]->tty_stopped = on_off;
1787                break;
1788        default:
1789                spk_parked &= 0xfe;
1790                spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1791                return;
1792        }
1793        if (on_off < 2)
1794                synth_printf("%s %s\n",
1795                             label, spk_msg_get(MSG_STATUS_START + on_off));
1796        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1797}
1798
1799static int inc_dec_var(u_char value)
1800{
1801        struct st_var_header *p_header;
1802        struct var_t *var_data;
1803        char num_buf[32];
1804        char *cp = num_buf;
1805        char *pn;
1806        int var_id = (int)value - VAR_START;
1807        int how = (var_id & 1) ? E_INC : E_DEC;
1808
1809        var_id = var_id / 2 + FIRST_SET_VAR;
1810        p_header = spk_get_var_header(var_id);
1811        if (p_header == NULL)
1812                return -1;
1813        if (p_header->var_type != VAR_NUM)
1814                return -1;
1815        var_data = p_header->data;
1816        if (spk_set_num_var(1, p_header, how) != 0)
1817                return -1;
1818        if (!spk_close_press) {
1819                for (pn = p_header->name; *pn; pn++) {
1820                        if (*pn == '_')
1821                                *cp = SPACE;
1822                        else
1823                                *cp++ = *pn;
1824                }
1825        }
1826        snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1827                 var_data->u.n.value);
1828        synth_printf("%s", num_buf);
1829        return 0;
1830}
1831
1832static void speakup_win_set(struct vc_data *vc)
1833{
1834        char info[40];
1835
1836        if (win_start > 1) {
1837                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1838                return;
1839        }
1840        if (spk_x < win_left || spk_y < win_top) {
1841                synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1842                return;
1843        }
1844        if (win_start && spk_x == win_left && spk_y == win_top) {
1845                win_left = 0;
1846                win_right = vc->vc_cols - 1;
1847                win_bottom = spk_y;
1848                snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1849                         (int)win_top + 1);
1850        } else {
1851                if (!win_start) {
1852                        win_top = spk_y;
1853                        win_left = spk_x;
1854                } else {
1855                        win_bottom = spk_y;
1856                        win_right = spk_x;
1857                }
1858                snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1859                         (win_start) ?
1860                                spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1861                         (int)spk_y + 1, (int)spk_x + 1);
1862        }
1863        synth_printf("%s\n", info);
1864        win_start++;
1865}
1866
1867static void speakup_win_clear(struct vc_data *vc)
1868{
1869        win_top = 0;
1870        win_bottom = 0;
1871        win_left = 0;
1872        win_right = 0;
1873        win_start = 0;
1874        synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1875}
1876
1877static void speakup_win_enable(struct vc_data *vc)
1878{
1879        if (win_start < 2) {
1880                synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1881                return;
1882        }
1883        win_enabled ^= 1;
1884        if (win_enabled)
1885                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1886        else
1887                synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1888}
1889
1890static void speakup_bits(struct vc_data *vc)
1891{
1892        int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1893
1894        if (spk_special_handler != NULL || val < 1 || val > 6) {
1895                synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1896                return;
1897        }
1898        pb_edit = &spk_punc_info[val];
1899        synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1900        spk_special_handler = edit_bits;
1901}
1902
1903static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1904{
1905        static u_char goto_buf[8];
1906        static int num;
1907        int maxlen;
1908        char *cp;
1909
1910        if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1911                goto do_goto;
1912        if (type == KT_LATIN && ch == '\n')
1913                goto do_goto;
1914        if (type != 0)
1915                goto oops;
1916        if (ch == 8) {
1917                if (num == 0)
1918                        return -1;
1919                ch = goto_buf[--num];
1920                goto_buf[num] = '\0';
1921                spkup_write(&ch, 1);
1922                return 1;
1923        }
1924        if (ch < '+' || ch > 'y')
1925                goto oops;
1926        goto_buf[num++] = ch;
1927        goto_buf[num] = '\0';
1928        spkup_write(&ch, 1);
1929        maxlen = (*goto_buf >= '0') ? 3 : 4;
1930        if ((ch == '+' || ch == '-') && num == 1)
1931                return 1;
1932        if (ch >= '0' && ch <= '9' && num < maxlen)
1933                return 1;
1934        if (num < maxlen - 1 || num > maxlen)
1935                goto oops;
1936        if (ch < 'x' || ch > 'y') {
1937oops:
1938                if (!spk_killed)
1939                        synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1940                goto_buf[num = 0] = '\0';
1941                spk_special_handler = NULL;
1942                return 1;
1943        }
1944
1945        goto_pos = simple_strtoul(goto_buf, &cp, 10);
1946
1947        if (*cp == 'x') {
1948                if (*goto_buf < '0')
1949                        goto_pos += spk_x;
1950                else if (goto_pos > 0)
1951                        goto_pos--;
1952
1953                if (goto_pos >= vc->vc_cols)
1954                        goto_pos = vc->vc_cols - 1;
1955                goto_x = 1;
1956        } else {
1957                if (*goto_buf < '0')
1958                        goto_pos += spk_y;
1959                else if (goto_pos > 0)
1960                        goto_pos--;
1961
1962                if (goto_pos >= vc->vc_rows)
1963                        goto_pos = vc->vc_rows - 1;
1964                goto_x = 0;
1965        }
1966        goto_buf[num = 0] = '\0';
1967do_goto:
1968        spk_special_handler = NULL;
1969        spk_parked |= 0x01;
1970        if (goto_x) {
1971                spk_pos -= spk_x * 2;
1972                spk_x = goto_pos;
1973                spk_pos += goto_pos * 2;
1974                say_word(vc);
1975        } else {
1976                spk_y = goto_pos;
1977                spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1978                say_line(vc);
1979        }
1980        return 1;
1981}
1982
1983static void speakup_goto(struct vc_data *vc)
1984{
1985        if (spk_special_handler != NULL) {
1986                synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1987                return;
1988        }
1989        synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1990        spk_special_handler = handle_goto;
1991}
1992
1993static void speakup_help(struct vc_data *vc)
1994{
1995        spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1996}
1997
1998static void do_nothing(struct vc_data *vc)
1999{
2000        return;                 /* flush done in do_spkup */
2001}
2002
2003static u_char key_speakup, spk_key_locked;
2004
2005static void speakup_lock(struct vc_data *vc)
2006{
2007        if (!spk_key_locked) {
2008                spk_key_locked = 16;
2009                key_speakup = 16;
2010        } else {
2011                spk_key_locked = 0;
2012                key_speakup = 0;
2013        }
2014}
2015
2016typedef void (*spkup_hand) (struct vc_data *);
2017static spkup_hand spkup_handler[] = {
2018        /* must be ordered same as defines in speakup.h */
2019        do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2020        speakup_cut, speakup_paste, say_first_char, say_last_char,
2021        say_char, say_prev_char, say_next_char,
2022        say_word, say_prev_word, say_next_word,
2023        say_line, say_prev_line, say_next_line,
2024        top_edge, bottom_edge, left_edge, right_edge,
2025        spell_word, spell_word, say_screen,
2026        say_position, say_attributes,
2027        speakup_off, speakup_parked, say_line,  /* this is for indent */
2028        say_from_top, say_to_bottom,
2029        say_from_left, say_to_right,
2030        say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2031        speakup_bits, speakup_bits, speakup_bits,
2032        speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2033        speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2034};
2035
2036static void do_spkup(struct vc_data *vc, u_char value)
2037{
2038        if (spk_killed && value != SPEECH_KILL)
2039                return;
2040        spk_keydown = 0;
2041        spk_lastkey = 0;
2042        spk_shut_up &= 0xfe;
2043        this_speakup_key = value;
2044        if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2045                spk_do_flush();
2046                (*spkup_handler[value]) (vc);
2047        } else {
2048                if (inc_dec_var(value) < 0)
2049                        bleep(9);
2050        }
2051}
2052
2053static const char *pad_chars = "0123456789+-*/\015,.?()";
2054
2055static int
2056speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2057            int up_flag)
2058{
2059        unsigned long flags;
2060        int kh;
2061        u_char *key_info;
2062        u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2063        u_char shift_info, offset;
2064        int ret = 0;
2065
2066        if (synth == NULL)
2067                return 0;
2068
2069        spin_lock_irqsave(&speakup_info.spinlock, flags);
2070        tty = vc->port.tty;
2071        if (type >= 0xf0)
2072                type -= 0xf0;
2073        if (type == KT_PAD
2074                && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2075                if (up_flag) {
2076                        spk_keydown = 0;
2077                        goto out;
2078                }
2079                value = spk_lastkey = pad_chars[value];
2080                spk_keydown++;
2081                spk_parked &= 0xfe;
2082                goto no_map;
2083        }
2084        if (keycode >= MAX_KEY)
2085                goto no_map;
2086        key_info = spk_our_keys[keycode];
2087        if (!key_info)
2088                goto no_map;
2089        /* Check valid read all mode keys */
2090        if ((cursor_track == read_all_mode) && (!up_flag)) {
2091                switch (value) {
2092                case KVAL(K_DOWN):
2093                case KVAL(K_UP):
2094                case KVAL(K_LEFT):
2095                case KVAL(K_RIGHT):
2096                case KVAL(K_PGUP):
2097                case KVAL(K_PGDN):
2098                        break;
2099                default:
2100                        stop_read_all(vc);
2101                        break;
2102                }
2103        }
2104        shift_info = (shift_state & 0x0f) + key_speakup;
2105        offset = spk_shift_table[shift_info];
2106        if (offset) {
2107                new_key = key_info[offset];
2108                if (new_key) {
2109                        ret = 1;
2110                        if (new_key == SPK_KEY) {
2111                                if (!spk_key_locked)
2112                                        key_speakup = (up_flag) ? 0 : 16;
2113                                if (up_flag || spk_killed)
2114                                        goto out;
2115                                spk_shut_up &= 0xfe;
2116                                spk_do_flush();
2117                                goto out;
2118                        }
2119                        if (up_flag)
2120                                goto out;
2121                        if (last_keycode == keycode &&
2122                            time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2123                                spk_close_press = 1;
2124                                offset = spk_shift_table[shift_info + 32];
2125                                /* double press? */
2126                                if (offset && key_info[offset])
2127                                        new_key = key_info[offset];
2128                        }
2129                        last_keycode = keycode;
2130                        last_spk_jiffy = jiffies;
2131                        type = KT_SPKUP;
2132                        value = new_key;
2133                }
2134        }
2135no_map:
2136        if (type == KT_SPKUP && spk_special_handler == NULL) {
2137                do_spkup(vc, new_key);
2138                spk_close_press = 0;
2139                ret = 1;
2140                goto out;
2141        }
2142        if (up_flag || spk_killed || type == KT_SHIFT)
2143                goto out;
2144        spk_shut_up &= 0xfe;
2145        kh = (value == KVAL(K_DOWN))
2146            || (value == KVAL(K_UP))
2147            || (value == KVAL(K_LEFT))
2148            || (value == KVAL(K_RIGHT));
2149        if ((cursor_track != read_all_mode) || !kh)
2150                if (!spk_no_intr)
2151                        spk_do_flush();
2152        if (spk_special_handler) {
2153                if (type == KT_SPEC && value == 1) {
2154                        value = '\n';
2155                        type = KT_LATIN;
2156                } else if (type == KT_LETTER)
2157                        type = KT_LATIN;
2158                else if (value == 0x7f)
2159                        value = 8;      /* make del = backspace */
2160                ret = (*spk_special_handler) (vc, type, value, keycode);
2161                spk_close_press = 0;
2162                if (ret < 0)
2163                        bleep(9);
2164                goto out;
2165        }
2166        last_keycode = 0;
2167out:
2168        spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2169        return ret;
2170}
2171
2172static int keyboard_notifier_call(struct notifier_block *nb,
2173                                  unsigned long code, void *_param)
2174{
2175        struct keyboard_notifier_param *param = _param;
2176        struct vc_data *vc = param->vc;
2177        int up = !param->down;
2178        int ret = NOTIFY_OK;
2179        static int keycode;     /* to hold the current keycode */
2180
2181        if (vc->vc_mode == KD_GRAPHICS)
2182                return ret;
2183
2184        /*
2185         * First, determine whether we are handling a fake keypress on
2186         * the current processor.  If we are, then return NOTIFY_OK,
2187         * to pass the keystroke up the chain.  This prevents us from
2188         * trying to take the Speakup lock while it is held by the
2189         * processor on which the simulated keystroke was generated.
2190         * Also, the simulated keystrokes should be ignored by Speakup.
2191         */
2192
2193        if (speakup_fake_key_pressed())
2194                return ret;
2195
2196        switch (code) {
2197        case KBD_KEYCODE:
2198                /* speakup requires keycode and keysym currently */
2199                keycode = param->value;
2200                break;
2201        case KBD_UNBOUND_KEYCODE:
2202                /* not used yet */
2203                break;
2204        case KBD_UNICODE:
2205                /* not used yet */
2206                break;
2207        case KBD_KEYSYM:
2208                if (speakup_key(vc, param->shift, keycode, param->value, up))
2209                        ret = NOTIFY_STOP;
2210                else if (KTYP(param->value) == KT_CUR)
2211                        ret = pre_handle_cursor(vc, KVAL(param->value), up);
2212                break;
2213        case KBD_POST_KEYSYM:{
2214                        unsigned char type = KTYP(param->value) - 0xf0;
2215                        unsigned char val = KVAL(param->value);
2216
2217                        switch (type) {
2218                        case KT_SHIFT:
2219                                do_handle_shift(vc, val, up);
2220                                break;
2221                        case KT_LATIN:
2222                        case KT_LETTER:
2223                                do_handle_latin(vc, val, up);
2224                                break;
2225                        case KT_CUR:
2226                                do_handle_cursor(vc, val, up);
2227                                break;
2228                        case KT_SPEC:
2229                                do_handle_spec(vc, val, up);
2230                                break;
2231                        }
2232                        break;
2233                }
2234        }
2235        return ret;
2236}
2237
2238static int vt_notifier_call(struct notifier_block *nb,
2239                            unsigned long code, void *_param)
2240{
2241        struct vt_notifier_param *param = _param;
2242        struct vc_data *vc = param->vc;
2243
2244        switch (code) {
2245        case VT_ALLOCATE:
2246                if (vc->vc_mode == KD_TEXT)
2247                        speakup_allocate(vc);
2248                break;
2249        case VT_DEALLOCATE:
2250                speakup_deallocate(vc);
2251                break;
2252        case VT_WRITE:
2253                if (param->c == '\b')
2254                        speakup_bs(vc);
2255                else if (param->c < 0x100) {
2256                        char d = param->c;
2257
2258                        speakup_con_write(vc, &d, 1);
2259                }
2260                break;
2261        case VT_UPDATE:
2262                speakup_con_update(vc);
2263                break;
2264        }
2265        return NOTIFY_OK;
2266}
2267
2268/* called by: module_exit() */
2269static void __exit speakup_exit(void)
2270{
2271        int i;
2272
2273        unregister_keyboard_notifier(&keyboard_notifier_block);
2274        unregister_vt_notifier(&vt_notifier_block);
2275        speakup_unregister_devsynth();
2276        speakup_cancel_paste();
2277        del_timer_sync(&cursor_timer);
2278        kthread_stop(speakup_task);
2279        speakup_task = NULL;
2280        mutex_lock(&spk_mutex);
2281        synth_release();
2282        mutex_unlock(&spk_mutex);
2283
2284        speakup_kobj_exit();
2285
2286        for (i = 0; i < MAX_NR_CONSOLES; i++)
2287                kfree(speakup_console[i]);
2288
2289        speakup_remove_virtual_keyboard();
2290
2291        for (i = 0; i < MAXVARS; i++)
2292                speakup_unregister_var(i);
2293
2294        for (i = 0; i < 256; i++) {
2295                if (spk_characters[i] != spk_default_chars[i])
2296                        kfree(spk_characters[i]);
2297        }
2298
2299        spk_free_user_msgs();
2300}
2301
2302/* call by: module_init() */
2303static int __init speakup_init(void)
2304{
2305        int i;
2306        long err = 0;
2307        struct st_spk_t *first_console;
2308        struct vc_data *vc = vc_cons[fg_console].d;
2309        struct var_t *var;
2310
2311        /* These first few initializations cannot fail. */
2312        spk_initialize_msgs();  /* Initialize arrays for i18n. */
2313        spk_reset_default_chars();
2314        spk_reset_default_chartab();
2315        spk_strlwr(synth_name);
2316        spk_vars[0].u.n.high = vc->vc_cols;
2317        for (var = spk_vars; var->var_id != MAXVARS; var++)
2318                speakup_register_var(var);
2319        for (var = synth_time_vars;
2320             (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2321                speakup_register_var(var);
2322        for (i = 1; spk_punc_info[i].mask != 0; i++)
2323                spk_set_mask_bits(NULL, i, 2);
2324
2325        spk_set_key_info(spk_key_defaults, spk_key_buf);
2326
2327        /* From here on out, initializations can fail. */
2328        err = speakup_add_virtual_keyboard();
2329        if (err)
2330                goto error_virtkeyboard;
2331
2332        first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2333        if (!first_console) {
2334                err = -ENOMEM;
2335                goto error_alloc;
2336        }
2337
2338        speakup_console[vc->vc_num] = first_console;
2339        speakup_date(vc);
2340
2341        for (i = 0; i < MAX_NR_CONSOLES; i++)
2342                if (vc_cons[i].d) {
2343                        err = speakup_allocate(vc_cons[i].d);
2344                        if (err)
2345                                goto error_kobjects;
2346                }
2347
2348        if (spk_quiet_boot)
2349                spk_shut_up |= 0x01;
2350
2351        err = speakup_kobj_init();
2352        if (err)
2353                goto error_kobjects;
2354
2355        synth_init(synth_name);
2356        speakup_register_devsynth();
2357        /*
2358         * register_devsynth might fail, but this error is not fatal.
2359         * /dev/synth is an extra feature; the rest of Speakup
2360         * will work fine without it.
2361         */
2362
2363        err = register_keyboard_notifier(&keyboard_notifier_block);
2364        if (err)
2365                goto error_kbdnotifier;
2366        err = register_vt_notifier(&vt_notifier_block);
2367        if (err)
2368                goto error_vtnotifier;
2369
2370        speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2371
2372        if (IS_ERR(speakup_task)) {
2373                err = PTR_ERR(speakup_task);
2374                goto error_task;
2375        }
2376
2377        set_user_nice(speakup_task, 10);
2378        wake_up_process(speakup_task);
2379
2380        pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2381        pr_info("synth name on entry is: %s\n", synth_name);
2382        goto out;
2383
2384error_task:
2385        unregister_vt_notifier(&vt_notifier_block);
2386
2387error_vtnotifier:
2388        unregister_keyboard_notifier(&keyboard_notifier_block);
2389        del_timer(&cursor_timer);
2390
2391error_kbdnotifier:
2392        speakup_unregister_devsynth();
2393        mutex_lock(&spk_mutex);
2394        synth_release();
2395        mutex_unlock(&spk_mutex);
2396        speakup_kobj_exit();
2397
2398error_kobjects:
2399        for (i = 0; i < MAX_NR_CONSOLES; i++)
2400                kfree(speakup_console[i]);
2401
2402error_alloc:
2403        speakup_remove_virtual_keyboard();
2404
2405error_virtkeyboard:
2406        for (i = 0; i < MAXVARS; i++)
2407                speakup_unregister_var(i);
2408
2409        for (i = 0; i < 256; i++) {
2410                if (spk_characters[i] != spk_default_chars[i])
2411                        kfree(spk_characters[i]);
2412        }
2413
2414        spk_free_user_msgs();
2415
2416out:
2417        return err;
2418}
2419
2420module_init(speakup_init);
2421module_exit(speakup_exit);
2422