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