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