Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* speakup.c
0003  * review functions for the speakup screen review package.
0004  * originally written by: Kirk Reiser and Andy Berdan.
0005  *
0006  * extensively modified by David Borowski.
0007  *
0008  ** Copyright (C) 1998  Kirk Reiser.
0009  *  Copyright (C) 2003  David Borowski.
0010  */
0011 
0012 #include <linux/kernel.h>
0013 #include <linux/vt.h>
0014 #include <linux/tty.h>
0015 #include <linux/mm.h>       /* __get_free_page() and friends */
0016 #include <linux/vt_kern.h>
0017 #include <linux/ctype.h>
0018 #include <linux/selection.h>
0019 #include <linux/unistd.h>
0020 #include <linux/jiffies.h>
0021 #include <linux/kthread.h>
0022 #include <linux/keyboard.h> /* for KT_SHIFT */
0023 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
0024 #include <linux/input.h>
0025 #include <linux/kmod.h>
0026 
0027 /* speakup_*_selection */
0028 #include <linux/module.h>
0029 #include <linux/sched.h>
0030 #include <linux/slab.h>
0031 #include <linux/types.h>
0032 #include <linux/consolemap.h>
0033 
0034 #include <linux/spinlock.h>
0035 #include <linux/notifier.h>
0036 
0037 #include <linux/uaccess.h>  /* copy_from|to|user() and others */
0038 
0039 #include "spk_priv.h"
0040 #include "speakup.h"
0041 
0042 #define MAX_DELAY msecs_to_jiffies(500)
0043 #define MINECHOCHAR SPACE
0044 
0045 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
0046 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
0047 MODULE_DESCRIPTION("Speakup console speech");
0048 MODULE_LICENSE("GPL");
0049 MODULE_VERSION(SPEAKUP_VERSION);
0050 
0051 char *synth_name;
0052 module_param_named(synth, synth_name, charp, 0444);
0053 module_param_named(quiet, spk_quiet_boot, bool, 0444);
0054 
0055 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
0056 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
0057 
0058 special_func spk_special_handler;
0059 
0060 short spk_pitch_shift, synth_flags;
0061 static u16 buf[256];
0062 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
0063 int spk_no_intr, spk_spell_delay;
0064 int spk_key_echo, spk_say_word_ctl;
0065 int spk_say_ctrl, spk_bell_pos;
0066 short spk_punc_mask;
0067 int spk_punc_level, spk_reading_punc;
0068 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
0069 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
0070 char spk_str_pause[MAXVARLEN + 1] = "\0";
0071 bool spk_paused;
0072 const struct st_bits_data spk_punc_info[] = {
0073     {"none", "", 0},
0074     {"some", "/$%&@", SOME},
0075     {"most", "$%&#()=+*/@^<>|\\", MOST},
0076     {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
0077     {"delimiters", "", B_WDLM},
0078     {"repeats", "()", CH_RPT},
0079     {"extended numeric", "", B_EXNUM},
0080     {"symbols", "", B_SYM},
0081     {NULL, NULL}
0082 };
0083 
0084 static char mark_cut_flag;
0085 #define MAX_KEY 160
0086 static u_char *spk_shift_table;
0087 u_char *spk_our_keys[MAX_KEY];
0088 u_char spk_key_buf[600];
0089 const u_char spk_key_defaults[] = {
0090 #include "speakupmap.h"
0091 };
0092 
0093 /* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */
0094 enum cursor_track {
0095     CT_Off = 0,
0096     CT_On,
0097     CT_Highlight,
0098     CT_Window,
0099     CT_Max,
0100     read_all_mode = CT_Max,
0101 };
0102 
0103 /* Speakup Cursor Track Variables */
0104 static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
0105 
0106 static struct tty_struct *tty;
0107 
0108 static void spkup_write(const u16 *in_buf, int count);
0109 
0110 static char *phonetic[] = {
0111     "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
0112     "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
0113         "papa",
0114     "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
0115     "x ray", "yankee", "zulu"
0116 };
0117 
0118 /* array of 256 char pointers (one for each character description)
0119  * initialized to default_chars and user selectable via
0120  * /proc/speakup/characters
0121  */
0122 char *spk_characters[256];
0123 
0124 char *spk_default_chars[256] = {
0125 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
0126 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
0127 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
0128 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
0129         "control",
0130 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
0131         "tick",
0132 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
0133         "dot",
0134     "slash",
0135 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
0136     "eight", "nine",
0137 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
0138 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
0139 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
0140 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
0141 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
0142         "caret",
0143     "line",
0144 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
0145 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
0146 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
0147 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
0148 /*127*/ "del", "control", "control", "control", "control", "control",
0149         "control", "control", "control", "control", "control",
0150 /*138*/ "control", "control", "control", "control", "control",
0151         "control", "control", "control", "control", "control",
0152         "control", "control",
0153 /*150*/ "control", "control", "control", "control", "control",
0154         "control", "control", "control", "control", "control",
0155 /*160*/ "nbsp", "inverted bang",
0156 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
0157 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
0158 /*172*/ "not", "soft hyphen", "registered", "macron",
0159 /*176*/ "degrees", "plus or minus", "super two", "super three",
0160 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
0161 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
0162 /*188*/ "one quarter", "one half", "three quarters",
0163         "inverted question",
0164 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
0165         "A RING",
0166 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
0167         "E OOMLAUT",
0168 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
0169         "N TILDE",
0170 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
0171 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
0172         "U CIRCUMFLEX",
0173 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
0174 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
0175 /*230*/ "ae", "c cidella", "e grave", "e acute",
0176 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
0177         "i circumflex",
0178 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
0179         "o circumflex",
0180 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
0181         "u acute",
0182 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
0183 };
0184 
0185 /* array of 256 u_short (one for each character)
0186  * initialized to default_chartab and user selectable via
0187  * /sys/module/speakup/parameters/chartab
0188  */
0189 u_short spk_chartab[256];
0190 
0191 static u_short default_chartab[256] = {
0192     B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
0193     B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
0194     B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
0195     B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
0196     WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /*  !"#$%&' */
0197     PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,   /* ()*+, -./ */
0198     NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
0199     NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,   /* 89:;<=>? */
0200     PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,  /* @ABCDEFG */
0201     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
0202     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
0203     A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,  /* XYZ[\]^_ */
0204     PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,  /* `abcdefg */
0205     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
0206     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
0207     ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
0208     B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
0209     B_SYM,  /* 135 */
0210     B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
0211     B_CAPSYM,   /* 143 */
0212     B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
0213     B_SYM,  /* 151 */
0214     B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
0215     B_SYM,  /* 159 */
0216     WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
0217     B_SYM,  /* 167 */
0218     B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
0219     B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
0220     B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
0221     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
0222     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
0223     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
0224     A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
0225     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
0226     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
0227     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
0228     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA  /* 248-255 */
0229 };
0230 
0231 struct task_struct *speakup_task;
0232 struct bleep spk_unprocessed_sound;
0233 static int spk_keydown;
0234 static u16 spk_lastkey;
0235 static u_char spk_close_press, keymap_flags;
0236 static u_char last_keycode, this_speakup_key;
0237 static u_long last_spk_jiffy;
0238 
0239 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
0240 
0241 DEFINE_MUTEX(spk_mutex);
0242 
0243 static int keyboard_notifier_call(struct notifier_block *,
0244                   unsigned long code, void *param);
0245 
0246 static struct notifier_block keyboard_notifier_block = {
0247     .notifier_call = keyboard_notifier_call,
0248 };
0249 
0250 static int vt_notifier_call(struct notifier_block *,
0251                 unsigned long code, void *param);
0252 
0253 static struct notifier_block vt_notifier_block = {
0254     .notifier_call = vt_notifier_call,
0255 };
0256 
0257 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
0258 {
0259     pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
0260     return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
0261 }
0262 
0263 static void speakup_date(struct vc_data *vc)
0264 {
0265     spk_x = spk_cx = vc->state.x;
0266     spk_y = spk_cy = vc->state.y;
0267     spk_pos = spk_cp = vc->vc_pos;
0268     spk_old_attr = spk_attr;
0269     spk_attr = get_attributes(vc, (u_short *)spk_pos);
0270 }
0271 
0272 static void bleep(u_short val)
0273 {
0274     static const short vals[] = {
0275         350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
0276     };
0277     short freq;
0278     int time = spk_bleep_time;
0279 
0280     freq = vals[val % 12];
0281     if (val > 11)
0282         freq *= (1 << (val / 12));
0283     spk_unprocessed_sound.freq = freq;
0284     spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
0285     spk_unprocessed_sound.active = 1;
0286     /* We can only have 1 active sound at a time. */
0287 }
0288 
0289 static void speakup_shut_up(struct vc_data *vc)
0290 {
0291     if (spk_killed)
0292         return;
0293     spk_shut_up |= 0x01;
0294     spk_parked &= 0xfe;
0295     speakup_date(vc);
0296     if (synth)
0297         spk_do_flush();
0298 }
0299 
0300 static void speech_kill(struct vc_data *vc)
0301 {
0302     char val = synth->is_alive(synth);
0303 
0304     if (val == 0)
0305         return;
0306 
0307     /* re-enables synth, if disabled */
0308     if (val == 2 || spk_killed) {
0309         /* dead */
0310         spk_shut_up &= ~0x40;
0311         synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
0312     } else {
0313         synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
0314         spk_shut_up |= 0x40;
0315     }
0316 }
0317 
0318 static void speakup_off(struct vc_data *vc)
0319 {
0320     if (spk_shut_up & 0x80) {
0321         spk_shut_up &= 0x7f;
0322         synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
0323     } else {
0324         spk_shut_up |= 0x80;
0325         synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
0326     }
0327     speakup_date(vc);
0328 }
0329 
0330 static void speakup_parked(struct vc_data *vc)
0331 {
0332     if (spk_parked & 0x80) {
0333         spk_parked = 0;
0334         synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
0335     } else {
0336         spk_parked |= 0x80;
0337         synth_printf("%s\n", spk_msg_get(MSG_PARKED));
0338     }
0339 }
0340 
0341 static void speakup_cut(struct vc_data *vc)
0342 {
0343     static const char err_buf[] = "set selection failed";
0344     int ret;
0345 
0346     if (!mark_cut_flag) {
0347         mark_cut_flag = 1;
0348         spk_xs = (u_short)spk_x;
0349         spk_ys = (u_short)spk_y;
0350         spk_sel_cons = vc;
0351         synth_printf("%s\n", spk_msg_get(MSG_MARK));
0352         return;
0353     }
0354     spk_xe = (u_short)spk_x;
0355     spk_ye = (u_short)spk_y;
0356     mark_cut_flag = 0;
0357     synth_printf("%s\n", spk_msg_get(MSG_CUT));
0358 
0359     ret = speakup_set_selection(tty);
0360 
0361     switch (ret) {
0362     case 0:
0363         break;      /* no error */
0364     case -EFAULT:
0365         pr_warn("%sEFAULT\n", err_buf);
0366         break;
0367     case -EINVAL:
0368         pr_warn("%sEINVAL\n", err_buf);
0369         break;
0370     case -ENOMEM:
0371         pr_warn("%sENOMEM\n", err_buf);
0372         break;
0373     }
0374 }
0375 
0376 static void speakup_paste(struct vc_data *vc)
0377 {
0378     if (mark_cut_flag) {
0379         mark_cut_flag = 0;
0380         synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
0381     } else {
0382         synth_printf("%s\n", spk_msg_get(MSG_PASTE));
0383         speakup_paste_selection(tty);
0384     }
0385 }
0386 
0387 static void say_attributes(struct vc_data *vc)
0388 {
0389     int fg = spk_attr & 0x0f;
0390     int bg = spk_attr >> 4;
0391 
0392     synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
0393     if (bg > 7) {
0394         synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
0395         bg -= 8;
0396     } else {
0397         synth_printf(" %s ", spk_msg_get(MSG_ON));
0398     }
0399     synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
0400 }
0401 
0402 /* must be ordered same as edge_msgs in enum msg_index_t */
0403 enum edge {
0404     edge_none = 0,
0405     edge_top,
0406     edge_bottom,
0407     edge_left,
0408     edge_right,
0409     edge_quiet
0410 };
0411 
0412 static void announce_edge(struct vc_data *vc, enum edge msg_id)
0413 {
0414     if (spk_bleeps & 1)
0415         bleep(spk_y);
0416     if ((spk_bleeps & 2) && (msg_id < edge_quiet))
0417         synth_printf("%s\n",
0418                  spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
0419 }
0420 
0421 static void speak_char(u16 ch)
0422 {
0423     char *cp;
0424     struct var_t *direct = spk_get_var(DIRECT);
0425 
0426     if (ch >= 0x100 || (direct && direct->u.n.value)) {
0427         if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
0428             spk_pitch_shift++;
0429             synth_printf("%s", spk_str_caps_start);
0430         }
0431         synth_putwc_s(ch);
0432         if (ch < 0x100 && IS_CHAR(ch, B_CAP))
0433             synth_printf("%s", spk_str_caps_stop);
0434         return;
0435     }
0436 
0437     cp = spk_characters[ch];
0438     if (!cp) {
0439         pr_info("%s: cp == NULL!\n", __func__);
0440         return;
0441     }
0442     if (IS_CHAR(ch, B_CAP)) {
0443         spk_pitch_shift++;
0444         synth_printf("%s %s %s",
0445                  spk_str_caps_start, cp, spk_str_caps_stop);
0446     } else {
0447         if (*cp == '^') {
0448             cp++;
0449             synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
0450         } else {
0451             synth_printf(" %s ", cp);
0452         }
0453     }
0454 }
0455 
0456 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
0457 {
0458     u16 ch = ' ';
0459 
0460     if (vc && pos) {
0461         u16 w;
0462         u16 c;
0463 
0464         pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
0465         w = scr_readw(pos);
0466         c = w & 0xff;
0467 
0468         if (w & vc->vc_hi_font_mask) {
0469             w &= ~vc->vc_hi_font_mask;
0470             c |= 0x100;
0471         }
0472 
0473         ch = inverse_translate(vc, c, true);
0474         *attribs = (w & 0xff00) >> 8;
0475     }
0476     return ch;
0477 }
0478 
0479 static void say_char(struct vc_data *vc)
0480 {
0481     u16 ch;
0482 
0483     spk_old_attr = spk_attr;
0484     ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
0485     if (spk_attr != spk_old_attr) {
0486         if (spk_attrib_bleep & 1)
0487             bleep(spk_y);
0488         if (spk_attrib_bleep & 2)
0489             say_attributes(vc);
0490     }
0491     speak_char(ch);
0492 }
0493 
0494 static void say_phonetic_char(struct vc_data *vc)
0495 {
0496     u16 ch;
0497 
0498     spk_old_attr = spk_attr;
0499     ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
0500     if (ch <= 0x7f && isalpha(ch)) {
0501         ch &= 0x1f;
0502         synth_printf("%s\n", phonetic[--ch]);
0503     } else {
0504         if (ch < 0x100 && IS_CHAR(ch, B_NUM))
0505             synth_printf("%s ", spk_msg_get(MSG_NUMBER));
0506         speak_char(ch);
0507     }
0508 }
0509 
0510 static void say_prev_char(struct vc_data *vc)
0511 {
0512     spk_parked |= 0x01;
0513     if (spk_x == 0) {
0514         announce_edge(vc, edge_left);
0515         return;
0516     }
0517     spk_x--;
0518     spk_pos -= 2;
0519     say_char(vc);
0520 }
0521 
0522 static void say_next_char(struct vc_data *vc)
0523 {
0524     spk_parked |= 0x01;
0525     if (spk_x == vc->vc_cols - 1) {
0526         announce_edge(vc, edge_right);
0527         return;
0528     }
0529     spk_x++;
0530     spk_pos += 2;
0531     say_char(vc);
0532 }
0533 
0534 /* get_word - will first check to see if the character under the
0535  * reading cursor is a space and if spk_say_word_ctl is true it will
0536  * return the word space.  If spk_say_word_ctl is not set it will check to
0537  * see if there is a word starting on the next position to the right
0538  * and return that word if it exists.  If it does not exist it will
0539  * move left to the beginning of any previous word on the line or the
0540  * beginning off the line whichever comes first..
0541  */
0542 
0543 static u_long get_word(struct vc_data *vc)
0544 {
0545     u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
0546     u16 ch;
0547     u16 attr_ch;
0548     u_char temp;
0549 
0550     spk_old_attr = spk_attr;
0551     ch = get_char(vc, (u_short *)tmp_pos, &temp);
0552 
0553 /* decided to take out the sayword if on a space (mis-information */
0554     if (spk_say_word_ctl && ch == SPACE) {
0555         *buf = '\0';
0556         synth_printf("%s\n", spk_msg_get(MSG_SPACE));
0557         return 0;
0558     } else if (tmpx < vc->vc_cols - 2 &&
0559            (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
0560            get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
0561         tmp_pos += 2;
0562         tmpx++;
0563     } else {
0564         while (tmpx > 0) {
0565             ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
0566             if ((ch == SPACE || ch == 0 ||
0567                  (ch < 0x100 && IS_WDLM(ch))) &&
0568                 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
0569                 break;
0570             tmp_pos -= 2;
0571             tmpx--;
0572         }
0573     }
0574     attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
0575     buf[cnt++] = attr_ch;
0576     while (tmpx < vc->vc_cols - 1) {
0577         tmp_pos += 2;
0578         tmpx++;
0579         ch = get_char(vc, (u_short *)tmp_pos, &temp);
0580         if (ch == SPACE || ch == 0 ||
0581             (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
0582              ch > SPACE))
0583             break;
0584         buf[cnt++] = ch;
0585     }
0586     buf[cnt] = '\0';
0587     return cnt;
0588 }
0589 
0590 static void say_word(struct vc_data *vc)
0591 {
0592     u_long cnt = get_word(vc);
0593     u_short saved_punc_mask = spk_punc_mask;
0594 
0595     if (cnt == 0)
0596         return;
0597     spk_punc_mask = PUNC;
0598     buf[cnt++] = SPACE;
0599     spkup_write(buf, cnt);
0600     spk_punc_mask = saved_punc_mask;
0601 }
0602 
0603 static void say_prev_word(struct vc_data *vc)
0604 {
0605     u_char temp;
0606     u16 ch;
0607     enum edge edge_said = edge_none;
0608     u_short last_state = 0, state = 0;
0609 
0610     spk_parked |= 0x01;
0611 
0612     if (spk_x == 0) {
0613         if (spk_y == 0) {
0614             announce_edge(vc, edge_top);
0615             return;
0616         }
0617         spk_y--;
0618         spk_x = vc->vc_cols;
0619         edge_said = edge_quiet;
0620     }
0621     while (1) {
0622         if (spk_x == 0) {
0623             if (spk_y == 0) {
0624                 edge_said = edge_top;
0625                 break;
0626             }
0627             if (edge_said != edge_quiet)
0628                 edge_said = edge_left;
0629             if (state > 0)
0630                 break;
0631             spk_y--;
0632             spk_x = vc->vc_cols - 1;
0633         } else {
0634             spk_x--;
0635         }
0636         spk_pos -= 2;
0637         ch = get_char(vc, (u_short *)spk_pos, &temp);
0638         if (ch == SPACE || ch == 0)
0639             state = 0;
0640         else if (ch < 0x100 && IS_WDLM(ch))
0641             state = 1;
0642         else
0643             state = 2;
0644         if (state < last_state) {
0645             spk_pos += 2;
0646             spk_x++;
0647             break;
0648         }
0649         last_state = state;
0650     }
0651     if (spk_x == 0 && edge_said == edge_quiet)
0652         edge_said = edge_left;
0653     if (edge_said > edge_none && edge_said < edge_quiet)
0654         announce_edge(vc, edge_said);
0655     say_word(vc);
0656 }
0657 
0658 static void say_next_word(struct vc_data *vc)
0659 {
0660     u_char temp;
0661     u16 ch;
0662     enum edge edge_said = edge_none;
0663     u_short last_state = 2, state = 0;
0664 
0665     spk_parked |= 0x01;
0666     if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
0667         announce_edge(vc, edge_bottom);
0668         return;
0669     }
0670     while (1) {
0671         ch = get_char(vc, (u_short *)spk_pos, &temp);
0672         if (ch == SPACE || ch == 0)
0673             state = 0;
0674         else if (ch < 0x100 && IS_WDLM(ch))
0675             state = 1;
0676         else
0677             state = 2;
0678         if (state > last_state)
0679             break;
0680         if (spk_x >= vc->vc_cols - 1) {
0681             if (spk_y == vc->vc_rows - 1) {
0682                 edge_said = edge_bottom;
0683                 break;
0684             }
0685             state = 0;
0686             spk_y++;
0687             spk_x = 0;
0688             edge_said = edge_right;
0689         } else {
0690             spk_x++;
0691         }
0692         spk_pos += 2;
0693         last_state = state;
0694     }
0695     if (edge_said > edge_none)
0696         announce_edge(vc, edge_said);
0697     say_word(vc);
0698 }
0699 
0700 static void spell_word(struct vc_data *vc)
0701 {
0702     static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
0703     u16 *cp = buf;
0704     char *cp1;
0705     char *str_cap = spk_str_caps_stop;
0706     char *last_cap = spk_str_caps_stop;
0707     struct var_t *direct = spk_get_var(DIRECT);
0708     u16 ch;
0709 
0710     if (!get_word(vc))
0711         return;
0712     while ((ch = *cp)) {
0713         if (cp != buf)
0714             synth_printf(" %s ", delay_str[spk_spell_delay]);
0715         /* FIXME: Non-latin1 considered as lower case */
0716         if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
0717             str_cap = spk_str_caps_start;
0718             if (*spk_str_caps_stop)
0719                 spk_pitch_shift++;
0720             else    /* synth has no pitch */
0721                 last_cap = spk_str_caps_stop;
0722         } else {
0723             str_cap = spk_str_caps_stop;
0724         }
0725         if (str_cap != last_cap) {
0726             synth_printf("%s", str_cap);
0727             last_cap = str_cap;
0728         }
0729         if (ch >= 0x100 || (direct && direct->u.n.value)) {
0730             synth_putwc_s(ch);
0731         } else if (this_speakup_key == SPELL_PHONETIC &&
0732             ch <= 0x7f && isalpha(ch)) {
0733             ch &= 0x1f;
0734             cp1 = phonetic[--ch];
0735             synth_printf("%s", cp1);
0736         } else {
0737             cp1 = spk_characters[ch];
0738             if (*cp1 == '^') {
0739                 synth_printf("%s", spk_msg_get(MSG_CTRL));
0740                 cp1++;
0741             }
0742             synth_printf("%s", cp1);
0743         }
0744         cp++;
0745     }
0746     if (str_cap != spk_str_caps_stop)
0747         synth_printf("%s", spk_str_caps_stop);
0748 }
0749 
0750 static int get_line(struct vc_data *vc)
0751 {
0752     u_long tmp = spk_pos - (spk_x * 2);
0753     int i = 0;
0754     u_char tmp2;
0755 
0756     spk_old_attr = spk_attr;
0757     spk_attr = get_attributes(vc, (u_short *)spk_pos);
0758     for (i = 0; i < vc->vc_cols; i++) {
0759         buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
0760         tmp += 2;
0761     }
0762     for (--i; i >= 0; i--)
0763         if (buf[i] != SPACE)
0764             break;
0765     return ++i;
0766 }
0767 
0768 static void say_line(struct vc_data *vc)
0769 {
0770     int i = get_line(vc);
0771     u16 *cp;
0772     u_short saved_punc_mask = spk_punc_mask;
0773 
0774     if (i == 0) {
0775         synth_printf("%s\n", spk_msg_get(MSG_BLANK));
0776         return;
0777     }
0778     buf[i++] = '\n';
0779     if (this_speakup_key == SAY_LINE_INDENT) {
0780         cp = buf;
0781         while (*cp == SPACE)
0782             cp++;
0783         synth_printf("%zd, ", (cp - buf) + 1);
0784     }
0785     spk_punc_mask = spk_punc_masks[spk_reading_punc];
0786     spkup_write(buf, i);
0787     spk_punc_mask = saved_punc_mask;
0788 }
0789 
0790 static void say_prev_line(struct vc_data *vc)
0791 {
0792     spk_parked |= 0x01;
0793     if (spk_y == 0) {
0794         announce_edge(vc, edge_top);
0795         return;
0796     }
0797     spk_y--;
0798     spk_pos -= vc->vc_size_row;
0799     say_line(vc);
0800 }
0801 
0802 static void say_next_line(struct vc_data *vc)
0803 {
0804     spk_parked |= 0x01;
0805     if (spk_y == vc->vc_rows - 1) {
0806         announce_edge(vc, edge_bottom);
0807         return;
0808     }
0809     spk_y++;
0810     spk_pos += vc->vc_size_row;
0811     say_line(vc);
0812 }
0813 
0814 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
0815                int read_punc)
0816 {
0817     int i = 0;
0818     u_char tmp;
0819     u_short saved_punc_mask = spk_punc_mask;
0820 
0821     spk_old_attr = spk_attr;
0822     spk_attr = get_attributes(vc, (u_short *)from);
0823     while (from < to) {
0824         buf[i++] = get_char(vc, (u_short *)from, &tmp);
0825         from += 2;
0826         if (i >= vc->vc_size_row)
0827             break;
0828     }
0829     for (--i; i >= 0; i--)
0830         if (buf[i] != SPACE)
0831             break;
0832     buf[++i] = SPACE;
0833     buf[++i] = '\0';
0834     if (i < 1)
0835         return i;
0836     if (read_punc)
0837         spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
0838     spkup_write(buf, i);
0839     if (read_punc)
0840         spk_punc_mask = saved_punc_mask;
0841     return i - 1;
0842 }
0843 
0844 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
0845                  int read_punc)
0846 {
0847     u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
0848     u_long end = start + (to * 2);
0849 
0850     start += from * 2;
0851     if (say_from_to(vc, start, end, read_punc) <= 0)
0852         if (cursor_track != read_all_mode)
0853             synth_printf("%s\n", spk_msg_get(MSG_BLANK));
0854 }
0855 
0856 /* Sentence Reading Commands */
0857 
0858 static int currsentence;
0859 static int numsentences[2];
0860 static u16 *sentbufend[2];
0861 static u16 *sentmarks[2][10];
0862 static int currbuf;
0863 static int bn;
0864 static u16 sentbuf[2][256];
0865 
0866 static int say_sentence_num(int num, int prev)
0867 {
0868     bn = currbuf;
0869     currsentence = num + 1;
0870     if (prev && --bn == -1)
0871         bn = 1;
0872 
0873     if (num > numsentences[bn])
0874         return 0;
0875 
0876     spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
0877     return 1;
0878 }
0879 
0880 static int get_sentence_buf(struct vc_data *vc, int read_punc)
0881 {
0882     u_long start, end;
0883     int i, bn;
0884     u_char tmp;
0885 
0886     currbuf++;
0887     if (currbuf == 2)
0888         currbuf = 0;
0889     bn = currbuf;
0890     start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
0891     end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
0892 
0893     numsentences[bn] = 0;
0894     sentmarks[bn][0] = &sentbuf[bn][0];
0895     i = 0;
0896     spk_old_attr = spk_attr;
0897     spk_attr = get_attributes(vc, (u_short *)start);
0898 
0899     while (start < end) {
0900         sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
0901         if (i > 0) {
0902             if (sentbuf[bn][i] == SPACE &&
0903                 sentbuf[bn][i - 1] == '.' &&
0904                 numsentences[bn] < 9) {
0905                 /* Sentence Marker */
0906                 numsentences[bn]++;
0907                 sentmarks[bn][numsentences[bn]] =
0908                     &sentbuf[bn][i];
0909             }
0910         }
0911         i++;
0912         start += 2;
0913         if (i >= vc->vc_size_row)
0914             break;
0915     }
0916 
0917     for (--i; i >= 0; i--)
0918         if (sentbuf[bn][i] != SPACE)
0919             break;
0920 
0921     if (i < 1)
0922         return -1;
0923 
0924     sentbuf[bn][++i] = SPACE;
0925     sentbuf[bn][++i] = '\0';
0926 
0927     sentbufend[bn] = &sentbuf[bn][i];
0928     return numsentences[bn];
0929 }
0930 
0931 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
0932 {
0933     u_long start = vc->vc_origin, end;
0934 
0935     if (from > 0)
0936         start += from * vc->vc_size_row;
0937     if (to > vc->vc_rows)
0938         to = vc->vc_rows;
0939     end = vc->vc_origin + (to * vc->vc_size_row);
0940     for (from = start; from < end; from = to) {
0941         to = from + vc->vc_size_row;
0942         say_from_to(vc, from, to, 1);
0943     }
0944 }
0945 
0946 static void say_screen(struct vc_data *vc)
0947 {
0948     say_screen_from_to(vc, 0, vc->vc_rows);
0949 }
0950 
0951 static void speakup_win_say(struct vc_data *vc)
0952 {
0953     u_long start, end, from, to;
0954 
0955     if (win_start < 2) {
0956         synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
0957         return;
0958     }
0959     start = vc->vc_origin + (win_top * vc->vc_size_row);
0960     end = vc->vc_origin + (win_bottom * vc->vc_size_row);
0961     while (start <= end) {
0962         from = start + (win_left * 2);
0963         to = start + (win_right * 2);
0964         say_from_to(vc, from, to, 1);
0965         start += vc->vc_size_row;
0966     }
0967 }
0968 
0969 static void top_edge(struct vc_data *vc)
0970 {
0971     spk_parked |= 0x01;
0972     spk_pos = vc->vc_origin + 2 * spk_x;
0973     spk_y = 0;
0974     say_line(vc);
0975 }
0976 
0977 static void bottom_edge(struct vc_data *vc)
0978 {
0979     spk_parked |= 0x01;
0980     spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
0981     spk_y = vc->vc_rows - 1;
0982     say_line(vc);
0983 }
0984 
0985 static void left_edge(struct vc_data *vc)
0986 {
0987     spk_parked |= 0x01;
0988     spk_pos -= spk_x * 2;
0989     spk_x = 0;
0990     say_char(vc);
0991 }
0992 
0993 static void right_edge(struct vc_data *vc)
0994 {
0995     spk_parked |= 0x01;
0996     spk_pos += (vc->vc_cols - spk_x - 1) * 2;
0997     spk_x = vc->vc_cols - 1;
0998     say_char(vc);
0999 }
1000 
1001 static void say_first_char(struct vc_data *vc)
1002 {
1003     int i, len = get_line(vc);
1004     u16 ch;
1005 
1006     spk_parked |= 0x01;
1007     if (len == 0) {
1008         synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1009         return;
1010     }
1011     for (i = 0; i < len; i++)
1012         if (buf[i] != SPACE)
1013             break;
1014     ch = buf[i];
1015     spk_pos -= (spk_x - i) * 2;
1016     spk_x = i;
1017     synth_printf("%d, ", ++i);
1018     speak_char(ch);
1019 }
1020 
1021 static void say_last_char(struct vc_data *vc)
1022 {
1023     int len = get_line(vc);
1024     u16 ch;
1025 
1026     spk_parked |= 0x01;
1027     if (len == 0) {
1028         synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1029         return;
1030     }
1031     ch = buf[--len];
1032     spk_pos -= (spk_x - len) * 2;
1033     spk_x = len;
1034     synth_printf("%d, ", ++len);
1035     speak_char(ch);
1036 }
1037 
1038 static void say_position(struct vc_data *vc)
1039 {
1040     synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1041              vc->vc_num + 1);
1042     synth_printf("\n");
1043 }
1044 
1045 /* Added by brianb */
1046 static void say_char_num(struct vc_data *vc)
1047 {
1048     u_char tmp;
1049     u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1050 
1051     synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1052 }
1053 
1054 /* these are stub functions to keep keyboard.c happy. */
1055 
1056 static void say_from_top(struct vc_data *vc)
1057 {
1058     say_screen_from_to(vc, 0, spk_y);
1059 }
1060 
1061 static void say_to_bottom(struct vc_data *vc)
1062 {
1063     say_screen_from_to(vc, spk_y, vc->vc_rows);
1064 }
1065 
1066 static void say_from_left(struct vc_data *vc)
1067 {
1068     say_line_from_to(vc, 0, spk_x, 1);
1069 }
1070 
1071 static void say_to_right(struct vc_data *vc)
1072 {
1073     say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1074 }
1075 
1076 /* end of stub functions. */
1077 
1078 static void spkup_write(const u16 *in_buf, int count)
1079 {
1080     static int rep_count;
1081     static u16 ch = '\0', old_ch = '\0';
1082     static u_short char_type, last_type;
1083     int in_count = count;
1084 
1085     spk_keydown = 0;
1086     while (count--) {
1087         if (cursor_track == read_all_mode) {
1088             /* Insert Sentence Index */
1089             if ((in_buf == sentmarks[bn][currsentence]) &&
1090                 (currsentence <= numsentences[bn]))
1091                 synth_insert_next_index(currsentence++);
1092         }
1093         ch = *in_buf++;
1094         if (ch < 0x100)
1095             char_type = spk_chartab[ch];
1096         else
1097             char_type = ALPHA;
1098         if (ch == old_ch && !(char_type & B_NUM)) {
1099             if (++rep_count > 2)
1100                 continue;
1101         } else {
1102             if ((last_type & CH_RPT) && rep_count > 2) {
1103                 synth_printf(" ");
1104                 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1105                          ++rep_count);
1106                 synth_printf(" ");
1107             }
1108             rep_count = 0;
1109         }
1110         if (ch == spk_lastkey) {
1111             rep_count = 0;
1112             if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1113                 speak_char(ch);
1114         } else if (char_type & B_ALPHA) {
1115             if ((synth_flags & SF_DEC) && (last_type & PUNC))
1116                 synth_buffer_add(SPACE);
1117             synth_putwc_s(ch);
1118         } else if (char_type & B_NUM) {
1119             rep_count = 0;
1120             synth_putwc_s(ch);
1121         } else if (char_type & spk_punc_mask) {
1122             speak_char(ch);
1123             char_type &= ~PUNC; /* for dec nospell processing */
1124         } else if (char_type & SYNTH_OK) {
1125             /* these are usually puncts like . and , which synth
1126              * needs for expression.
1127              * suppress multiple to get rid of long pauses and
1128              * clear repeat count
1129              * so if someone has
1130              * repeats on you don't get nothing repeated count
1131              */
1132             if (ch != old_ch)
1133                 synth_putwc_s(ch);
1134             else
1135                 rep_count = 0;
1136         } else {
1137 /* send space and record position, if next is num overwrite space */
1138             if (old_ch != ch)
1139                 synth_buffer_add(SPACE);
1140             else
1141                 rep_count = 0;
1142         }
1143         old_ch = ch;
1144         last_type = char_type;
1145     }
1146     spk_lastkey = 0;
1147     if (in_count > 2 && rep_count > 2) {
1148         if (last_type & CH_RPT) {
1149             synth_printf(" ");
1150             synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1151                      ++rep_count);
1152             synth_printf(" ");
1153         }
1154         rep_count = 0;
1155     }
1156 }
1157 
1158 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1159 
1160 static void read_all_doc(struct vc_data *vc);
1161 static void cursor_done(struct timer_list *unused);
1162 static DEFINE_TIMER(cursor_timer, cursor_done);
1163 
1164 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1165 {
1166     unsigned long flags;
1167 
1168     if (!synth || up_flag || spk_killed)
1169         return;
1170     spin_lock_irqsave(&speakup_info.spinlock, flags);
1171     if (cursor_track == read_all_mode) {
1172         switch (value) {
1173         case KVAL(K_SHIFT):
1174             del_timer(&cursor_timer);
1175             spk_shut_up &= 0xfe;
1176             spk_do_flush();
1177             read_all_doc(vc);
1178             break;
1179         case KVAL(K_CTRL):
1180             del_timer(&cursor_timer);
1181             cursor_track = prev_cursor_track;
1182             spk_shut_up &= 0xfe;
1183             spk_do_flush();
1184             break;
1185         }
1186     } else {
1187         spk_shut_up &= 0xfe;
1188         spk_do_flush();
1189     }
1190     if (spk_say_ctrl && value < NUM_CTL_LABELS)
1191         synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1192     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1193 }
1194 
1195 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1196 {
1197     unsigned long flags;
1198 
1199     spin_lock_irqsave(&speakup_info.spinlock, flags);
1200     if (up_flag) {
1201         spk_lastkey = 0;
1202         spk_keydown = 0;
1203         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1204         return;
1205     }
1206     if (!synth || spk_killed) {
1207         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1208         return;
1209     }
1210     spk_shut_up &= 0xfe;
1211     spk_lastkey = value;
1212     spk_keydown++;
1213     spk_parked &= 0xfe;
1214     if (spk_key_echo == 2 && value >= MINECHOCHAR)
1215         speak_char(value);
1216     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1217 }
1218 
1219 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1220 {
1221     int i = 0, states, key_data_len;
1222     const u_char *cp = key_info;
1223     u_char *cp1 = k_buffer;
1224     u_char ch, version, num_keys;
1225 
1226     version = *cp++;
1227     if (version != KEY_MAP_VER) {
1228         pr_debug("version found %d should be %d\n",
1229              version, KEY_MAP_VER);
1230         return -EINVAL;
1231     }
1232     num_keys = *cp;
1233     states = (int)cp[1];
1234     key_data_len = (states + 1) * (num_keys + 1);
1235     if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1236         pr_debug("too many key_infos (%d over %u)\n",
1237              key_data_len + SHIFT_TBL_SIZE + 4,
1238              (unsigned int)(sizeof(spk_key_buf)));
1239         return -EINVAL;
1240     }
1241     memset(k_buffer, 0, SHIFT_TBL_SIZE);
1242     memset(spk_our_keys, 0, sizeof(spk_our_keys));
1243     spk_shift_table = k_buffer;
1244     spk_our_keys[0] = spk_shift_table;
1245     cp1 += SHIFT_TBL_SIZE;
1246     memcpy(cp1, cp, key_data_len + 3);
1247     /* get num_keys, states and data */
1248     cp1 += 2;       /* now pointing at shift states */
1249     for (i = 1; i <= states; i++) {
1250         ch = *cp1++;
1251         if (ch >= SHIFT_TBL_SIZE) {
1252             pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
1253                  ch, SHIFT_TBL_SIZE);
1254             return -EINVAL;
1255         }
1256         spk_shift_table[ch] = i;
1257     }
1258     keymap_flags = *cp1++;
1259     while ((ch = *cp1)) {
1260         if (ch >= MAX_KEY) {
1261             pr_debug("(%d), not valid key, (max_allowed = %d)\n",
1262                  ch, MAX_KEY);
1263             return -EINVAL;
1264         }
1265         spk_our_keys[ch] = cp1;
1266         cp1 += states + 1;
1267     }
1268     return 0;
1269 }
1270 
1271 static struct var_t spk_vars[] = {
1272     /* bell must be first to set high limit */
1273     {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1274     {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1275     {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1276     {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1277     {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1278     {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1279     {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1280     {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1281     {SAY_CONTROL, TOGGLE_0},
1282     {SAY_WORD_CTL, TOGGLE_0},
1283     {NO_INTERRUPT, TOGGLE_0},
1284     {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1285     V_LAST_VAR
1286 };
1287 
1288 static void toggle_cursoring(struct vc_data *vc)
1289 {
1290     if (cursor_track == read_all_mode)
1291         cursor_track = prev_cursor_track;
1292     if (++cursor_track >= CT_Max)
1293         cursor_track = 0;
1294     synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1295 }
1296 
1297 void spk_reset_default_chars(void)
1298 {
1299     int i;
1300 
1301     /* First, free any non-default */
1302     for (i = 0; i < 256; i++) {
1303         if (spk_characters[i] &&
1304             (spk_characters[i] != spk_default_chars[i]))
1305             kfree(spk_characters[i]);
1306     }
1307 
1308     memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1309 }
1310 
1311 void spk_reset_default_chartab(void)
1312 {
1313     memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1314 }
1315 
1316 static const struct st_bits_data *pb_edit;
1317 
1318 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1319 {
1320     short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1321 
1322     if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1323         return -1;
1324     if (ch == SPACE) {
1325         synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1326         spk_special_handler = NULL;
1327         return 1;
1328     }
1329     if (mask < PUNC && !(ch_type & PUNC))
1330         return -1;
1331     spk_chartab[ch] ^= mask;
1332     speak_char(ch);
1333     synth_printf(" %s\n",
1334              (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1335              spk_msg_get(MSG_OFF));
1336     return 1;
1337 }
1338 
1339 /* Allocation concurrency is protected by the console semaphore */
1340 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1341 {
1342     int vc_num;
1343 
1344     vc_num = vc->vc_num;
1345     if (!speakup_console[vc_num]) {
1346         speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1347                           gfp_flags);
1348         if (!speakup_console[vc_num])
1349             return -ENOMEM;
1350         speakup_date(vc);
1351     } else if (!spk_parked) {
1352         speakup_date(vc);
1353     }
1354 
1355     return 0;
1356 }
1357 
1358 static void speakup_deallocate(struct vc_data *vc)
1359 {
1360     int vc_num;
1361 
1362     vc_num = vc->vc_num;
1363     kfree(speakup_console[vc_num]);
1364     speakup_console[vc_num] = NULL;
1365 }
1366 
1367 enum read_all_command {
1368     RA_NEXT_SENT = KVAL(K_DOWN)+1,
1369     RA_PREV_LINE = KVAL(K_LEFT)+1,
1370     RA_NEXT_LINE = KVAL(K_RIGHT)+1,
1371     RA_PREV_SENT = KVAL(K_UP)+1,
1372     RA_DOWN_ARROW,
1373     RA_TIMER,
1374     RA_FIND_NEXT_SENT,
1375     RA_FIND_PREV_SENT,
1376 };
1377 
1378 static u_char is_cursor;
1379 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1380 static int cursor_con;
1381 
1382 static void reset_highlight_buffers(struct vc_data *);
1383 
1384 static enum read_all_command read_all_key;
1385 
1386 static int in_keyboard_notifier;
1387 
1388 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1389 
1390 static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
1391 {
1392     del_timer(&cursor_timer);
1393     speakup_fake_down_arrow();
1394     start_read_all_timer(vc, command);
1395 }
1396 
1397 static void read_all_doc(struct vc_data *vc)
1398 {
1399     if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1400         return;
1401     if (!synth_supports_indexing())
1402         return;
1403     if (cursor_track != read_all_mode)
1404         prev_cursor_track = cursor_track;
1405     cursor_track = read_all_mode;
1406     spk_reset_index_count(0);
1407     if (get_sentence_buf(vc, 0) == -1) {
1408         del_timer(&cursor_timer);
1409         if (!in_keyboard_notifier)
1410             speakup_fake_down_arrow();
1411         start_read_all_timer(vc, RA_DOWN_ARROW);
1412     } else {
1413         say_sentence_num(0, 0);
1414         synth_insert_next_index(0);
1415         start_read_all_timer(vc, RA_TIMER);
1416     }
1417 }
1418 
1419 static void stop_read_all(struct vc_data *vc)
1420 {
1421     del_timer(&cursor_timer);
1422     cursor_track = prev_cursor_track;
1423     spk_shut_up &= 0xfe;
1424     spk_do_flush();
1425 }
1426 
1427 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
1428 {
1429     struct var_t *cursor_timeout;
1430 
1431     cursor_con = vc->vc_num;
1432     read_all_key = command;
1433     cursor_timeout = spk_get_var(CURSOR_TIME);
1434     mod_timer(&cursor_timer,
1435           jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1436 }
1437 
1438 static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
1439 {
1440     int indcount, sentcount, rv, sn;
1441 
1442     switch (command) {
1443     case RA_NEXT_SENT:
1444         /* Get Current Sentence */
1445         spk_get_index_count(&indcount, &sentcount);
1446         /*printk("%d %d  ", indcount, sentcount); */
1447         spk_reset_index_count(sentcount + 1);
1448         if (indcount == 1) {
1449             if (!say_sentence_num(sentcount + 1, 0)) {
1450                 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1451                 return;
1452             }
1453             synth_insert_next_index(0);
1454         } else {
1455             sn = 0;
1456             if (!say_sentence_num(sentcount + 1, 1)) {
1457                 sn = 1;
1458                 spk_reset_index_count(sn);
1459             } else {
1460                 synth_insert_next_index(0);
1461             }
1462             if (!say_sentence_num(sn, 0)) {
1463                 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1464                 return;
1465             }
1466             synth_insert_next_index(0);
1467         }
1468         start_read_all_timer(vc, RA_TIMER);
1469         break;
1470     case RA_PREV_SENT:
1471         break;
1472     case RA_NEXT_LINE:
1473         read_all_doc(vc);
1474         break;
1475     case RA_PREV_LINE:
1476         break;
1477     case RA_DOWN_ARROW:
1478         if (get_sentence_buf(vc, 0) == -1) {
1479             kbd_fakekey2(vc, RA_DOWN_ARROW);
1480         } else {
1481             say_sentence_num(0, 0);
1482             synth_insert_next_index(0);
1483             start_read_all_timer(vc, RA_TIMER);
1484         }
1485         break;
1486     case RA_FIND_NEXT_SENT:
1487         rv = get_sentence_buf(vc, 0);
1488         if (rv == -1)
1489             read_all_doc(vc);
1490         if (rv == 0) {
1491             kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1492         } else {
1493             say_sentence_num(1, 0);
1494             synth_insert_next_index(0);
1495             start_read_all_timer(vc, RA_TIMER);
1496         }
1497         break;
1498     case RA_FIND_PREV_SENT:
1499         break;
1500     case RA_TIMER:
1501         spk_get_index_count(&indcount, &sentcount);
1502         if (indcount < 2)
1503             kbd_fakekey2(vc, RA_DOWN_ARROW);
1504         else
1505             start_read_all_timer(vc, RA_TIMER);
1506         break;
1507     }
1508 }
1509 
1510 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1511 {
1512     unsigned long flags;
1513 
1514     spin_lock_irqsave(&speakup_info.spinlock, flags);
1515     if (cursor_track == read_all_mode) {
1516         spk_parked &= 0xfe;
1517         if (!synth || up_flag || spk_shut_up) {
1518             spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1519             return NOTIFY_STOP;
1520         }
1521         del_timer(&cursor_timer);
1522         spk_shut_up &= 0xfe;
1523         spk_do_flush();
1524         start_read_all_timer(vc, value + 1);
1525         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1526         return NOTIFY_STOP;
1527     }
1528     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1529     return NOTIFY_OK;
1530 }
1531 
1532 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1533 {
1534     unsigned long flags;
1535     struct var_t *cursor_timeout;
1536 
1537     spin_lock_irqsave(&speakup_info.spinlock, flags);
1538     spk_parked &= 0xfe;
1539     if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1540         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1541         return;
1542     }
1543     spk_shut_up &= 0xfe;
1544     if (spk_no_intr)
1545         spk_do_flush();
1546 /* the key press flushes if !no_inter but we want to flush on cursor
1547  * moves regardless of no_inter state
1548  */
1549     is_cursor = value + 1;
1550     old_cursor_pos = vc->vc_pos;
1551     old_cursor_x = vc->state.x;
1552     old_cursor_y = vc->state.y;
1553     speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1554     cursor_con = vc->vc_num;
1555     if (cursor_track == CT_Highlight)
1556         reset_highlight_buffers(vc);
1557     cursor_timeout = spk_get_var(CURSOR_TIME);
1558     mod_timer(&cursor_timer,
1559           jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1560     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1561 }
1562 
1563 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1564 {
1565     int i, bi, hi;
1566     int vc_num = vc->vc_num;
1567 
1568     bi = (vc->vc_attr & 0x70) >> 4;
1569     hi = speakup_console[vc_num]->ht.highsize[bi];
1570 
1571     i = 0;
1572     if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1573         speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1574         speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1575         speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1576     }
1577     while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1578         if (ic[i] > 32) {
1579             speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1580             hi++;
1581         } else if ((ic[i] == 32) && (hi != 0)) {
1582             if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1583                 32) {
1584                 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1585                     ic[i];
1586                 hi++;
1587             }
1588         }
1589         i++;
1590     }
1591     speakup_console[vc_num]->ht.highsize[bi] = hi;
1592 }
1593 
1594 static void reset_highlight_buffers(struct vc_data *vc)
1595 {
1596     int i;
1597     int vc_num = vc->vc_num;
1598 
1599     for (i = 0; i < 8; i++)
1600         speakup_console[vc_num]->ht.highsize[i] = 0;
1601 }
1602 
1603 static int count_highlight_color(struct vc_data *vc)
1604 {
1605     int i, bg;
1606     int cc;
1607     int vc_num = vc->vc_num;
1608     u16 ch;
1609     u16 *start = (u16 *)vc->vc_origin;
1610 
1611     for (i = 0; i < 8; i++)
1612         speakup_console[vc_num]->ht.bgcount[i] = 0;
1613 
1614     for (i = 0; i < vc->vc_rows; i++) {
1615         u16 *end = start + vc->vc_cols * 2;
1616         u16 *ptr;
1617 
1618         for (ptr = start; ptr < end; ptr++) {
1619             ch = get_attributes(vc, ptr);
1620             bg = (ch & 0x70) >> 4;
1621             speakup_console[vc_num]->ht.bgcount[bg]++;
1622         }
1623         start += vc->vc_size_row;
1624     }
1625 
1626     cc = 0;
1627     for (i = 0; i < 8; i++)
1628         if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1629             cc++;
1630     return cc;
1631 }
1632 
1633 static int get_highlight_color(struct vc_data *vc)
1634 {
1635     int i, j;
1636     unsigned int cptr[8];
1637     int vc_num = vc->vc_num;
1638 
1639     for (i = 0; i < 8; i++)
1640         cptr[i] = i;
1641 
1642     for (i = 0; i < 7; i++)
1643         for (j = i + 1; j < 8; j++)
1644             if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1645                 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1646                 swap(cptr[i], cptr[j]);
1647 
1648     for (i = 0; i < 8; i++)
1649         if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1650             if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1651                 return cptr[i];
1652     return -1;
1653 }
1654 
1655 static int speak_highlight(struct vc_data *vc)
1656 {
1657     int hc, d;
1658     int vc_num = vc->vc_num;
1659 
1660     if (count_highlight_color(vc) == 1)
1661         return 0;
1662     hc = get_highlight_color(vc);
1663     if (hc != -1) {
1664         d = vc->state.y - speakup_console[vc_num]->ht.cy;
1665         if ((d == 1) || (d == -1))
1666             if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1667                 return 0;
1668         spk_parked |= 0x01;
1669         spk_do_flush();
1670         spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1671                 speakup_console[vc_num]->ht.highsize[hc]);
1672         spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1673         spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1674         spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1675         return 1;
1676     }
1677     return 0;
1678 }
1679 
1680 static void cursor_done(struct timer_list *unused)
1681 {
1682     struct vc_data *vc = vc_cons[cursor_con].d;
1683     unsigned long flags;
1684 
1685     del_timer(&cursor_timer);
1686     spin_lock_irqsave(&speakup_info.spinlock, flags);
1687     if (cursor_con != fg_console) {
1688         is_cursor = 0;
1689         goto out;
1690     }
1691     speakup_date(vc);
1692     if (win_enabled) {
1693         if (vc->state.x >= win_left && vc->state.x <= win_right &&
1694             vc->state.y >= win_top && vc->state.y <= win_bottom) {
1695             spk_keydown = 0;
1696             is_cursor = 0;
1697             goto out;
1698         }
1699     }
1700     if (cursor_track == read_all_mode) {
1701         handle_cursor_read_all(vc, read_all_key);
1702         goto out;
1703     }
1704     if (cursor_track == CT_Highlight) {
1705         if (speak_highlight(vc)) {
1706             spk_keydown = 0;
1707             is_cursor = 0;
1708             goto out;
1709         }
1710     }
1711     if (cursor_track == CT_Window)
1712         speakup_win_say(vc);
1713     else if (is_cursor == 1 || is_cursor == 4)
1714         say_line_from_to(vc, 0, vc->vc_cols, 0);
1715     else
1716         say_char(vc);
1717     spk_keydown = 0;
1718     is_cursor = 0;
1719 out:
1720     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1721 }
1722 
1723 /* called by: vt_notifier_call() */
1724 static void speakup_bs(struct vc_data *vc)
1725 {
1726     unsigned long flags;
1727 
1728     if (!speakup_console[vc->vc_num])
1729         return;
1730     if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1731         /* Speakup output, discard */
1732         return;
1733     if (!spk_parked)
1734         speakup_date(vc);
1735     if (spk_shut_up || !synth) {
1736         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1737         return;
1738     }
1739     if (vc->vc_num == fg_console && spk_keydown) {
1740         spk_keydown = 0;
1741         if (!is_cursor)
1742             say_char(vc);
1743     }
1744     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1745 }
1746 
1747 /* called by: vt_notifier_call() */
1748 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1749 {
1750     unsigned long flags;
1751 
1752     if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1753         return;
1754     if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1755         /* Speakup output, discard */
1756         return;
1757     if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1758         bleep(3);
1759     if ((is_cursor) || (cursor_track == read_all_mode)) {
1760         if (cursor_track == CT_Highlight)
1761             update_color_buffer(vc, str, len);
1762         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1763         return;
1764     }
1765     if (win_enabled) {
1766         if (vc->state.x >= win_left && vc->state.x <= win_right &&
1767             vc->state.y >= win_top && vc->state.y <= win_bottom) {
1768             spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1769             return;
1770         }
1771     }
1772 
1773     spkup_write(str, len);
1774     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1775 }
1776 
1777 static void speakup_con_update(struct vc_data *vc)
1778 {
1779     unsigned long flags;
1780 
1781     if (!speakup_console[vc->vc_num] || spk_parked)
1782         return;
1783     if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1784         /* Speakup output, discard */
1785         return;
1786     speakup_date(vc);
1787     if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1788         synth_printf("%s", spk_str_pause);
1789         spk_paused = true;
1790     }
1791     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1792 }
1793 
1794 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1795 {
1796     unsigned long flags;
1797     int on_off = 2;
1798     char *label;
1799 
1800     if (!synth || up_flag || spk_killed)
1801         return;
1802     spin_lock_irqsave(&speakup_info.spinlock, flags);
1803     spk_shut_up &= 0xfe;
1804     if (spk_no_intr)
1805         spk_do_flush();
1806     switch (value) {
1807     case KVAL(K_CAPS):
1808         label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1809         on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1810         break;
1811     case KVAL(K_NUM):
1812         label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1813         on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1814         break;
1815     case KVAL(K_HOLD):
1816         label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1817         on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1818         if (speakup_console[vc->vc_num])
1819             speakup_console[vc->vc_num]->tty_stopped = on_off;
1820         break;
1821     default:
1822         spk_parked &= 0xfe;
1823         spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1824         return;
1825     }
1826     if (on_off < 2)
1827         synth_printf("%s %s\n",
1828                  label, spk_msg_get(MSG_STATUS_START + on_off));
1829     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1830 }
1831 
1832 static int inc_dec_var(u_char value)
1833 {
1834     struct st_var_header *p_header;
1835     struct var_t *var_data;
1836     char num_buf[32];
1837     char *cp = num_buf;
1838     char *pn;
1839     int var_id = (int)value - VAR_START;
1840     int how = (var_id & 1) ? E_INC : E_DEC;
1841 
1842     var_id = var_id / 2 + FIRST_SET_VAR;
1843     p_header = spk_get_var_header(var_id);
1844     if (!p_header)
1845         return -1;
1846     if (p_header->var_type != VAR_NUM)
1847         return -1;
1848     var_data = p_header->data;
1849     if (spk_set_num_var(1, p_header, how) != 0)
1850         return -1;
1851     if (!spk_close_press) {
1852         for (pn = p_header->name; *pn; pn++) {
1853             if (*pn == '_')
1854                 *cp = SPACE;
1855             else
1856                 *cp++ = *pn;
1857         }
1858     }
1859     snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1860          var_data->u.n.value);
1861     synth_printf("%s", num_buf);
1862     return 0;
1863 }
1864 
1865 static void speakup_win_set(struct vc_data *vc)
1866 {
1867     char info[40];
1868 
1869     if (win_start > 1) {
1870         synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1871         return;
1872     }
1873     if (spk_x < win_left || spk_y < win_top) {
1874         synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1875         return;
1876     }
1877     if (win_start && spk_x == win_left && spk_y == win_top) {
1878         win_left = 0;
1879         win_right = vc->vc_cols - 1;
1880         win_bottom = spk_y;
1881         snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1882              (int)win_top + 1);
1883     } else {
1884         if (!win_start) {
1885             win_top = spk_y;
1886             win_left = spk_x;
1887         } else {
1888             win_bottom = spk_y;
1889             win_right = spk_x;
1890         }
1891         snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1892              (win_start) ?
1893                 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1894              (int)spk_y + 1, (int)spk_x + 1);
1895     }
1896     synth_printf("%s\n", info);
1897     win_start++;
1898 }
1899 
1900 static void speakup_win_clear(struct vc_data *vc)
1901 {
1902     win_top = 0;
1903     win_bottom = 0;
1904     win_left = 0;
1905     win_right = 0;
1906     win_start = 0;
1907     synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1908 }
1909 
1910 static void speakup_win_enable(struct vc_data *vc)
1911 {
1912     if (win_start < 2) {
1913         synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1914         return;
1915     }
1916     win_enabled ^= 1;
1917     if (win_enabled)
1918         synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1919     else
1920         synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1921 }
1922 
1923 static void speakup_bits(struct vc_data *vc)
1924 {
1925     int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1926 
1927     if (spk_special_handler || val < 1 || val > 6) {
1928         synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1929         return;
1930     }
1931     pb_edit = &spk_punc_info[val];
1932     synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1933     spk_special_handler = edit_bits;
1934 }
1935 
1936 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1937 {
1938     static u_char goto_buf[8];
1939     static int num;
1940     int maxlen;
1941     char *cp;
1942     u16 wch;
1943 
1944     if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1945         goto do_goto;
1946     if (type == KT_LATIN && ch == '\n')
1947         goto do_goto;
1948     if (type != 0)
1949         goto oops;
1950     if (ch == 8) {
1951         u16 wch;
1952 
1953         if (num == 0)
1954             return -1;
1955         wch = goto_buf[--num];
1956         goto_buf[num] = '\0';
1957         spkup_write(&wch, 1);
1958         return 1;
1959     }
1960     if (ch < '+' || ch > 'y')
1961         goto oops;
1962     wch = ch;
1963     goto_buf[num++] = ch;
1964     goto_buf[num] = '\0';
1965     spkup_write(&wch, 1);
1966     maxlen = (*goto_buf >= '0') ? 3 : 4;
1967     if ((ch == '+' || ch == '-') && num == 1)
1968         return 1;
1969     if (ch >= '0' && ch <= '9' && num < maxlen)
1970         return 1;
1971     if (num < maxlen - 1 || num > maxlen)
1972         goto oops;
1973     if (ch < 'x' || ch > 'y') {
1974 oops:
1975         if (!spk_killed)
1976             synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1977         goto_buf[num = 0] = '\0';
1978         spk_special_handler = NULL;
1979         return 1;
1980     }
1981 
1982     /* Do not replace with kstrtoul: here we need cp to be updated */
1983     goto_pos = simple_strtoul(goto_buf, &cp, 10);
1984 
1985     if (*cp == 'x') {
1986         if (*goto_buf < '0')
1987             goto_pos += spk_x;
1988         else if (goto_pos > 0)
1989             goto_pos--;
1990 
1991         if (goto_pos >= vc->vc_cols)
1992             goto_pos = vc->vc_cols - 1;
1993         goto_x = 1;
1994     } else {
1995         if (*goto_buf < '0')
1996             goto_pos += spk_y;
1997         else if (goto_pos > 0)
1998             goto_pos--;
1999 
2000         if (goto_pos >= vc->vc_rows)
2001             goto_pos = vc->vc_rows - 1;
2002         goto_x = 0;
2003     }
2004     goto_buf[num = 0] = '\0';
2005 do_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 
2021 static 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 
2031 static void speakup_help(struct vc_data *vc)
2032 {
2033     spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2034 }
2035 
2036 static void do_nothing(struct vc_data *vc)
2037 {
2038     return;         /* flush done in do_spkup */
2039 }
2040 
2041 static u_char key_speakup, spk_key_locked;
2042 
2043 static 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 
2054 typedef void (*spkup_hand) (struct vc_data *);
2055 static 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 
2074 static 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 
2091 static const char *pad_chars = "0123456789+-*/\015,.?()";
2092 
2093 static int
2094 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2095         int up_flag)
2096 {
2097     unsigned long flags;
2098     int kh;
2099     u_char *key_info;
2100     u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2101     u_char shift_info, offset;
2102     int ret = 0;
2103 
2104     if (!synth)
2105         return 0;
2106 
2107     spin_lock_irqsave(&speakup_info.spinlock, flags);
2108     tty = vc->port.tty;
2109     if (type >= 0xf0)
2110         type -= 0xf0;
2111     if (type == KT_PAD &&
2112         (vt_get_leds(fg_console, VC_NUMLOCK))) {
2113         if (up_flag) {
2114             spk_keydown = 0;
2115             goto out;
2116         }
2117         value = pad_chars[value];
2118         spk_lastkey = value;
2119         spk_keydown++;
2120         spk_parked &= 0xfe;
2121         goto no_map;
2122     }
2123     if (keycode >= MAX_KEY)
2124         goto no_map;
2125     key_info = spk_our_keys[keycode];
2126     if (!key_info)
2127         goto no_map;
2128     /* Check valid read all mode keys */
2129     if ((cursor_track == read_all_mode) && (!up_flag)) {
2130         switch (value) {
2131         case KVAL(K_DOWN):
2132         case KVAL(K_UP):
2133         case KVAL(K_LEFT):
2134         case KVAL(K_RIGHT):
2135         case KVAL(K_PGUP):
2136         case KVAL(K_PGDN):
2137             break;
2138         default:
2139             stop_read_all(vc);
2140             break;
2141         }
2142     }
2143     shift_info = (shift_state & 0x0f) + key_speakup;
2144     offset = spk_shift_table[shift_info];
2145     if (offset) {
2146         new_key = key_info[offset];
2147         if (new_key) {
2148             ret = 1;
2149             if (new_key == SPK_KEY) {
2150                 if (!spk_key_locked)
2151                     key_speakup = (up_flag) ? 0 : 16;
2152                 if (up_flag || spk_killed)
2153                     goto out;
2154                 spk_shut_up &= 0xfe;
2155                 spk_do_flush();
2156                 goto out;
2157             }
2158             if (up_flag)
2159                 goto out;
2160             if (last_keycode == keycode &&
2161                 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2162                 spk_close_press = 1;
2163                 offset = spk_shift_table[shift_info + 32];
2164                 /* double press? */
2165                 if (offset && key_info[offset])
2166                     new_key = key_info[offset];
2167             }
2168             last_keycode = keycode;
2169             last_spk_jiffy = jiffies;
2170             type = KT_SPKUP;
2171             value = new_key;
2172         }
2173     }
2174 no_map:
2175     if (type == KT_SPKUP && !spk_special_handler) {
2176         do_spkup(vc, new_key);
2177         spk_close_press = 0;
2178         ret = 1;
2179         goto out;
2180     }
2181     if (up_flag || spk_killed || type == KT_SHIFT)
2182         goto out;
2183     spk_shut_up &= 0xfe;
2184     kh = (value == KVAL(K_DOWN)) ||
2185         (value == KVAL(K_UP)) ||
2186         (value == KVAL(K_LEFT)) ||
2187         (value == KVAL(K_RIGHT));
2188     if ((cursor_track != read_all_mode) || !kh)
2189         if (!spk_no_intr)
2190             spk_do_flush();
2191     if (spk_special_handler) {
2192         if (type == KT_SPEC && value == 1) {
2193             value = '\n';
2194             type = KT_LATIN;
2195         } else if (type == KT_LETTER) {
2196             type = KT_LATIN;
2197         } else if (value == 0x7f) {
2198             value = 8;  /* make del = backspace */
2199         }
2200         ret = (*spk_special_handler) (vc, type, value, keycode);
2201         spk_close_press = 0;
2202         if (ret < 0)
2203             bleep(9);
2204         goto out;
2205     }
2206     last_keycode = 0;
2207 out:
2208     spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2209     return ret;
2210 }
2211 
2212 static int keyboard_notifier_call(struct notifier_block *nb,
2213                   unsigned long code, void *_param)
2214 {
2215     struct keyboard_notifier_param *param = _param;
2216     struct vc_data *vc = param->vc;
2217     int up = !param->down;
2218     int ret = NOTIFY_OK;
2219     static int keycode; /* to hold the current keycode */
2220 
2221     in_keyboard_notifier = 1;
2222 
2223     if (vc->vc_mode == KD_GRAPHICS)
2224         goto out;
2225 
2226     /*
2227      * First, determine whether we are handling a fake keypress on
2228      * the current processor.  If we are, then return NOTIFY_OK,
2229      * to pass the keystroke up the chain.  This prevents us from
2230      * trying to take the Speakup lock while it is held by the
2231      * processor on which the simulated keystroke was generated.
2232      * Also, the simulated keystrokes should be ignored by Speakup.
2233      */
2234 
2235     if (speakup_fake_key_pressed())
2236         goto out;
2237 
2238     switch (code) {
2239     case KBD_KEYCODE:
2240         /* speakup requires keycode and keysym currently */
2241         keycode = param->value;
2242         break;
2243     case KBD_UNBOUND_KEYCODE:
2244         /* not used yet */
2245         break;
2246     case KBD_UNICODE:
2247         /* not used yet */
2248         break;
2249     case KBD_KEYSYM:
2250         if (speakup_key(vc, param->shift, keycode, param->value, up))
2251             ret = NOTIFY_STOP;
2252         else if (KTYP(param->value) == KT_CUR)
2253             ret = pre_handle_cursor(vc, KVAL(param->value), up);
2254         break;
2255     case KBD_POST_KEYSYM:{
2256             unsigned char type = KTYP(param->value) - 0xf0;
2257             unsigned char val = KVAL(param->value);
2258 
2259             switch (type) {
2260             case KT_SHIFT:
2261                 do_handle_shift(vc, val, up);
2262                 break;
2263             case KT_LATIN:
2264             case KT_LETTER:
2265                 do_handle_latin(vc, val, up);
2266                 break;
2267             case KT_CUR:
2268                 do_handle_cursor(vc, val, up);
2269                 break;
2270             case KT_SPEC:
2271                 do_handle_spec(vc, val, up);
2272                 break;
2273             }
2274             break;
2275         }
2276     }
2277 out:
2278     in_keyboard_notifier = 0;
2279     return ret;
2280 }
2281 
2282 static int vt_notifier_call(struct notifier_block *nb,
2283                 unsigned long code, void *_param)
2284 {
2285     struct vt_notifier_param *param = _param;
2286     struct vc_data *vc = param->vc;
2287 
2288     switch (code) {
2289     case VT_ALLOCATE:
2290         if (vc->vc_mode == KD_TEXT)
2291             speakup_allocate(vc, GFP_ATOMIC);
2292         break;
2293     case VT_DEALLOCATE:
2294         speakup_deallocate(vc);
2295         break;
2296     case VT_WRITE:
2297         if (param->c == '\b') {
2298             speakup_bs(vc);
2299         } else {
2300             u16 d = param->c;
2301 
2302             speakup_con_write(vc, &d, 1);
2303         }
2304         break;
2305     case VT_UPDATE:
2306         speakup_con_update(vc);
2307         break;
2308     }
2309     return NOTIFY_OK;
2310 }
2311 
2312 /* called by: module_exit() */
2313 static void __exit speakup_exit(void)
2314 {
2315     int i;
2316 
2317     unregister_keyboard_notifier(&keyboard_notifier_block);
2318     unregister_vt_notifier(&vt_notifier_block);
2319     speakup_unregister_devsynth();
2320     speakup_cancel_selection();
2321     speakup_cancel_paste();
2322     del_timer_sync(&cursor_timer);
2323     kthread_stop(speakup_task);
2324     speakup_task = NULL;
2325     mutex_lock(&spk_mutex);
2326     synth_release();
2327     mutex_unlock(&spk_mutex);
2328     spk_ttyio_unregister_ldisc();
2329 
2330     speakup_kobj_exit();
2331 
2332     for (i = 0; i < MAX_NR_CONSOLES; i++)
2333         kfree(speakup_console[i]);
2334 
2335     speakup_remove_virtual_keyboard();
2336 
2337     for (i = 0; i < MAXVARS; i++)
2338         speakup_unregister_var(i);
2339 
2340     for (i = 0; i < 256; i++) {
2341         if (spk_characters[i] != spk_default_chars[i])
2342             kfree(spk_characters[i]);
2343     }
2344 
2345     spk_free_user_msgs();
2346 }
2347 
2348 /* call by: module_init() */
2349 static int __init speakup_init(void)
2350 {
2351     int i;
2352     long err = 0;
2353     struct vc_data *vc = vc_cons[fg_console].d;
2354     struct var_t *var;
2355 
2356     /* These first few initializations cannot fail. */
2357     spk_initialize_msgs();  /* Initialize arrays for i18n. */
2358     spk_reset_default_chars();
2359     spk_reset_default_chartab();
2360     spk_strlwr(synth_name);
2361     spk_vars[0].u.n.high = vc->vc_cols;
2362     for (var = spk_vars; var->var_id != MAXVARS; var++)
2363         speakup_register_var(var);
2364     for (var = synth_time_vars;
2365          (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2366         speakup_register_var(var);
2367     for (i = 1; spk_punc_info[i].mask != 0; i++)
2368         spk_set_mask_bits(NULL, i, 2);
2369 
2370     spk_set_key_info(spk_key_defaults, spk_key_buf);
2371 
2372     /* From here on out, initializations can fail. */
2373     err = speakup_add_virtual_keyboard();
2374     if (err)
2375         goto error_virtkeyboard;
2376 
2377     for (i = 0; i < MAX_NR_CONSOLES; i++)
2378         if (vc_cons[i].d) {
2379             err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2380             if (err)
2381                 goto error_kobjects;
2382         }
2383 
2384     if (spk_quiet_boot)
2385         spk_shut_up |= 0x01;
2386 
2387     err = speakup_kobj_init();
2388     if (err)
2389         goto error_kobjects;
2390 
2391     spk_ttyio_register_ldisc();
2392     synth_init(synth_name);
2393     speakup_register_devsynth();
2394     /*
2395      * register_devsynth might fail, but this error is not fatal.
2396      * /dev/synth is an extra feature; the rest of Speakup
2397      * will work fine without it.
2398      */
2399 
2400     err = register_keyboard_notifier(&keyboard_notifier_block);
2401     if (err)
2402         goto error_kbdnotifier;
2403     err = register_vt_notifier(&vt_notifier_block);
2404     if (err)
2405         goto error_vtnotifier;
2406 
2407     speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2408 
2409     if (IS_ERR(speakup_task)) {
2410         err = PTR_ERR(speakup_task);
2411         goto error_task;
2412     }
2413 
2414     set_user_nice(speakup_task, 10);
2415     wake_up_process(speakup_task);
2416 
2417     pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2418     pr_info("synth name on entry is: %s\n", synth_name);
2419     goto out;
2420 
2421 error_task:
2422     unregister_vt_notifier(&vt_notifier_block);
2423 
2424 error_vtnotifier:
2425     unregister_keyboard_notifier(&keyboard_notifier_block);
2426     del_timer(&cursor_timer);
2427 
2428 error_kbdnotifier:
2429     speakup_unregister_devsynth();
2430     mutex_lock(&spk_mutex);
2431     synth_release();
2432     mutex_unlock(&spk_mutex);
2433     speakup_kobj_exit();
2434 
2435 error_kobjects:
2436     for (i = 0; i < MAX_NR_CONSOLES; i++)
2437         kfree(speakup_console[i]);
2438 
2439     speakup_remove_virtual_keyboard();
2440 
2441 error_virtkeyboard:
2442     for (i = 0; i < MAXVARS; i++)
2443         speakup_unregister_var(i);
2444 
2445     for (i = 0; i < 256; i++) {
2446         if (spk_characters[i] != spk_default_chars[i])
2447             kfree(spk_characters[i]);
2448     }
2449 
2450     spk_free_user_msgs();
2451 
2452 out:
2453     return err;
2454 }
2455 
2456 module_init(speakup_init);
2457 module_exit(speakup_exit);