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