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