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