]> Pileus Git - ~andy/linux/blob - drivers/staging/speakup/main.c
cd981a13c12d49074a480c3094b07bbbbf0dcbe2
[~andy/linux] / drivers / staging / speakup / main.c
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
61 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
62 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
63 MODULE_DESCRIPTION("Speakup console speech");
64 MODULE_LICENSE("GPL");
65 MODULE_VERSION(SPEAKUP_VERSION);
66
67 char *synth_name;
68 module_param_named(synth, synth_name, charp, S_IRUGO);
69 module_param_named(quiet, quiet_boot, bool, S_IRUGO);
70
71 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
72 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
73
74 special_func special_handler;
75
76 short pitch_shift, synth_flags;
77 static char buf[256];
78 int attrib_bleep, bleeps, bleep_time = 10;
79 int no_intr, spell_delay;
80 int key_echo, say_word_ctl;
81 int say_ctrl, bell_pos;
82 short punc_mask;
83 int punc_level, reading_punc;
84 char str_caps_start[MAXVARLEN + 1] = "\0", str_caps_stop[MAXVARLEN + 1] = "\0";
85 const 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
97 static char mark_cut_flag;
98 #define MAX_KEY 160
99 u_char *our_keys[MAX_KEY], *shift_table;
100 u_char key_buf[600];
101 const u_char key_defaults[] = {
102 #include "speakupmap.h"
103 };
104
105 /* Speakup Cursor Track Variables */
106 static int cursor_track = 1, prev_cursor_track = 1;
107
108 /* cursor track modes, must be ordered same as cursor_msgs */
109 enum {
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
118 static struct tty_struct *tty;
119
120 static void spkup_write(const char *in_buf, int count);
121
122 static 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 */
133 char *characters[256];
134
135 char *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 */
199 u_short spk_chartab[256];
200
201 static 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
241 struct task_struct *speakup_task;
242 struct bleep unprocessed_sound;
243 static int spk_keydown;
244 static u_char spk_lastkey, spk_close_press, keymap_flags;
245 static u_char last_keycode, this_speakup_key;
246 static u_long last_spk_jiffy;
247
248 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
249
250 DEFINE_MUTEX(spk_mutex);
251
252 static int keyboard_notifier_call(struct notifier_block *,
253                                   unsigned long code, void *param);
254
255 struct notifier_block keyboard_notifier_block = {
256         .notifier_call = keyboard_notifier_call,
257 };
258
259 static int vt_notifier_call(struct notifier_block *,
260                             unsigned long code, void *param);
261
262 struct notifier_block vt_notifier_block = {
263         .notifier_call = vt_notifier_call,
264 };
265
266 static unsigned char get_attributes(u16 *pos)
267 {
268         return (u_char) (scr_readw(pos) >> 8);
269 }
270
271 static 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
280 static 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
296 static 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
307 static 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
324 static 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
336 static 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
347 static 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
383 static 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
394 static 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
411 enum {
412         edge_top = 1,
413         edge_bottom,
414         edge_left,
415         edge_right,
416         edge_quiet
417 };
418
419 static 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
427 static 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
461 static 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
477 static 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
491 static 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
506 static 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
518 static 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
538 static 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
583 static 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
595 static 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
647 static 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
687 static 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
728 static 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
746 static 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
767 static 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
779 static 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
791 static 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
820 static 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
833 static int currsentence;
834 static int numsentences[2];
835 static char *sentbufend[2];
836 static char *sentmarks[2][10];
837 static int currbuf;
838 static int bn;
839 static char sentbuf[2][256];
840
841 static 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
855 static 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
905 static 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
919 static void say_screen(struct vc_data *vc)
920 {
921         say_screen_from_to(vc, 0, vc->vc_rows);
922 }
923
924 static 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
941 static 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
949 static 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
957 static 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
965 static 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
973 static 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
992 static 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
1008 static 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 */
1016 static 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
1026 static void say_from_top(struct vc_data *vc)
1027 {
1028         say_screen_from_to(vc, 0, spk_y);
1029 }
1030
1031 static void say_to_bottom(struct vc_data *vc)
1032 {
1033         say_screen_from_to(vc, spk_y, vc->vc_rows);
1034 }
1035
1036 static void say_from_left(struct vc_data *vc)
1037 {
1038         say_line_from_to(vc, 0, spk_x, 1);
1039 }
1040
1041 static 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
1048 static 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
1122 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1123
1124 static void read_all_doc(struct vc_data *vc);
1125 static void cursor_done(u_long data);
1126 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1127
1128 static 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
1158 static 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
1180 int 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
1218 static 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
1235 static 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
1244 void 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
1258 void reset_default_chartab(void)
1259 {
1260         memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1261 }
1262
1263 static const struct st_bits_data *pb_edit;
1264
1265 static 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 */
1286 int 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 -ENOMEM;
1296                 speakup_date(vc);
1297         } else if (!spk_parked)
1298                 speakup_date(vc);
1299
1300         return 0;
1301 }
1302
1303 void speakup_deallocate(struct vc_data *vc)
1304 {
1305         int vc_num;
1306
1307         vc_num = vc->vc_num;
1308         if (speakup_console[vc_num] != NULL) {
1309                 kfree(speakup_console[vc_num]);
1310                 speakup_console[vc_num] = NULL;
1311         }
1312 }
1313
1314 static u_char is_cursor;
1315 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1316 static int cursor_con;
1317
1318 static void reset_highlight_buffers(struct vc_data *);
1319
1320 static int read_all_key;
1321
1322 static void start_read_all_timer(struct vc_data *vc, int command);
1323
1324 enum {
1325         RA_NOTHING,
1326         RA_NEXT_SENT,
1327         RA_PREV_LINE,
1328         RA_NEXT_LINE,
1329         RA_PREV_SENT,
1330         RA_DOWN_ARROW,
1331         RA_TIMER,
1332         RA_FIND_NEXT_SENT,
1333         RA_FIND_PREV_SENT,
1334 };
1335
1336 static void kbd_fakekey2(struct vc_data *vc, int command)
1337 {
1338         del_timer(&cursor_timer);
1339         speakup_fake_down_arrow();
1340         start_read_all_timer(vc, command);
1341 }
1342
1343 static void read_all_doc(struct vc_data *vc)
1344 {
1345         if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1346                 return;
1347         if (!synth_supports_indexing())
1348                 return;
1349         if (cursor_track != read_all_mode)
1350                 prev_cursor_track = cursor_track;
1351         cursor_track = read_all_mode;
1352         reset_index_count(0);
1353         if (get_sentence_buf(vc, 0) == -1)
1354                 kbd_fakekey2(vc, RA_DOWN_ARROW);
1355         else {
1356                 say_sentence_num(0, 0);
1357                 synth_insert_next_index(0);
1358                 start_read_all_timer(vc, RA_TIMER);
1359         }
1360 }
1361
1362 static void stop_read_all(struct vc_data *vc)
1363 {
1364         del_timer(&cursor_timer);
1365         cursor_track = prev_cursor_track;
1366         spk_shut_up &= 0xfe;
1367         do_flush();
1368 }
1369
1370 static void start_read_all_timer(struct vc_data *vc, int command)
1371 {
1372         struct var_t *cursor_timeout;
1373
1374         cursor_con = vc->vc_num;
1375         read_all_key = command;
1376         cursor_timeout = get_var(CURSOR_TIME);
1377         mod_timer(&cursor_timer,
1378                   jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1379 }
1380
1381 static void handle_cursor_read_all(struct vc_data *vc, int command)
1382 {
1383         int indcount, sentcount, rv, sn;
1384
1385         switch (command) {
1386         case RA_NEXT_SENT:
1387                 /* Get Current Sentence */
1388                 get_index_count(&indcount, &sentcount);
1389                 /*printk("%d %d  ", indcount, sentcount); */
1390                 reset_index_count(sentcount + 1);
1391                 if (indcount == 1) {
1392                         if (!say_sentence_num(sentcount + 1, 0)) {
1393                                 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1394                                 return;
1395                         }
1396                         synth_insert_next_index(0);
1397                 } else {
1398                         sn = 0;
1399                         if (!say_sentence_num(sentcount + 1, 1)) {
1400                                 sn = 1;
1401                                 reset_index_count(sn);
1402                         } else
1403                                 synth_insert_next_index(0);
1404                         if (!say_sentence_num(sn, 0)) {
1405                                 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1406                                 return;
1407                         }
1408                         synth_insert_next_index(0);
1409                 }
1410                 start_read_all_timer(vc, RA_TIMER);
1411                 break;
1412         case RA_PREV_SENT:
1413                 break;
1414         case RA_NEXT_LINE:
1415                 read_all_doc(vc);
1416                 break;
1417         case RA_PREV_LINE:
1418                 break;
1419         case RA_DOWN_ARROW:
1420                 if (get_sentence_buf(vc, 0) == -1) {
1421                         kbd_fakekey2(vc, RA_DOWN_ARROW);
1422                 } else {
1423                         say_sentence_num(0, 0);
1424                         synth_insert_next_index(0);
1425                         start_read_all_timer(vc, RA_TIMER);
1426                 }
1427                 break;
1428         case RA_FIND_NEXT_SENT:
1429                 rv = get_sentence_buf(vc, 0);
1430                 if (rv == -1)
1431                         read_all_doc(vc);
1432                 if (rv == 0)
1433                         kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1434                 else {
1435                         say_sentence_num(1, 0);
1436                         synth_insert_next_index(0);
1437                         start_read_all_timer(vc, RA_TIMER);
1438                 }
1439                 break;
1440         case RA_FIND_PREV_SENT:
1441                 break;
1442         case RA_TIMER:
1443                 get_index_count(&indcount, &sentcount);
1444                 if (indcount < 2)
1445                         kbd_fakekey2(vc, RA_DOWN_ARROW);
1446                 else
1447                         start_read_all_timer(vc, RA_TIMER);
1448                 break;
1449         }
1450 }
1451
1452 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1453 {
1454         unsigned long flags;
1455         spk_lock(flags);
1456         if (cursor_track == read_all_mode) {
1457                 spk_parked &= 0xfe;
1458                 if (synth == NULL || up_flag || spk_shut_up) {
1459                         spk_unlock(flags);
1460                         return NOTIFY_STOP;
1461                 }
1462                 del_timer(&cursor_timer);
1463                 spk_shut_up &= 0xfe;
1464                 do_flush();
1465                 start_read_all_timer(vc, value + 1);
1466                 spk_unlock(flags);
1467                 return NOTIFY_STOP;
1468         }
1469         spk_unlock(flags);
1470         return NOTIFY_OK;
1471 }
1472
1473 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1474 {
1475         unsigned long flags;
1476         struct var_t *cursor_timeout;
1477
1478         spk_lock(flags);
1479         spk_parked &= 0xfe;
1480         if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1481                 spk_unlock(flags);
1482                 return;
1483         }
1484         spk_shut_up &= 0xfe;
1485         if (no_intr)
1486                 do_flush();
1487 /* the key press flushes if !no_inter but we want to flush on cursor
1488  * moves regardless of no_inter state */
1489         is_cursor = value + 1;
1490         old_cursor_pos = vc->vc_pos;
1491         old_cursor_x = vc->vc_x;
1492         old_cursor_y = vc->vc_y;
1493         speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1494         cursor_con = vc->vc_num;
1495         if (cursor_track == CT_Highlight)
1496                 reset_highlight_buffers(vc);
1497         cursor_timeout = get_var(CURSOR_TIME);
1498         mod_timer(&cursor_timer,
1499                   jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1500         spk_unlock(flags);
1501 }
1502
1503 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1504 {
1505         int i, bi, hi;
1506         int vc_num = vc->vc_num;
1507
1508         bi = ((vc->vc_attr & 0x70) >> 4);
1509         hi = speakup_console[vc_num]->ht.highsize[bi];
1510
1511         i = 0;
1512         if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1513                 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1514                 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1515                 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1516         }
1517         while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1518                 if ((ic[i] > 32) && (ic[i] < 127)) {
1519                         speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1520                         hi++;
1521                 } else if ((ic[i] == 32) && (hi != 0)) {
1522                         if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1523                             32) {
1524                                 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1525                                     ic[i];
1526                                 hi++;
1527                         }
1528                 }
1529                 i++;
1530         }
1531         speakup_console[vc_num]->ht.highsize[bi] = hi;
1532 }
1533
1534 static void reset_highlight_buffers(struct vc_data *vc)
1535 {
1536         int i;
1537         int vc_num = vc->vc_num;
1538         for (i = 0; i < 8; i++)
1539                 speakup_console[vc_num]->ht.highsize[i] = 0;
1540 }
1541
1542 static int count_highlight_color(struct vc_data *vc)
1543 {
1544         int i, bg;
1545         int cc;
1546         int vc_num = vc->vc_num;
1547         u16 ch;
1548         u16 *start = (u16 *) vc->vc_origin;
1549
1550         for (i = 0; i < 8; i++)
1551                 speakup_console[vc_num]->ht.bgcount[i] = 0;
1552
1553         for (i = 0; i < vc->vc_rows; i++) {
1554                 u16 *end = start + vc->vc_cols * 2;
1555                 u16 *ptr;
1556                 for (ptr = start; ptr < end; ptr++) {
1557                         ch = get_attributes(ptr);
1558                         bg = (ch & 0x70) >> 4;
1559                         speakup_console[vc_num]->ht.bgcount[bg]++;
1560                 }
1561                 start += vc->vc_size_row;
1562         }
1563
1564         cc = 0;
1565         for (i = 0; i < 8; i++)
1566                 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1567                         cc++;
1568         return cc;
1569 }
1570
1571 static int get_highlight_color(struct vc_data *vc)
1572 {
1573         int i, j;
1574         unsigned int cptr[8], tmp;
1575         int vc_num = vc->vc_num;
1576
1577         for (i = 0; i < 8; i++)
1578                 cptr[i] = i;
1579
1580         for (i = 0; i < 7; i++)
1581                 for (j = i + 1; j < 8; j++)
1582                         if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1583                             speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1584                                 tmp = cptr[i];
1585                                 cptr[i] = cptr[j];
1586                                 cptr[j] = tmp;
1587                         }
1588
1589         for (i = 0; i < 8; i++)
1590                 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1591                         if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1592                                 return cptr[i];
1593         return -1;
1594 }
1595
1596 static int speak_highlight(struct vc_data *vc)
1597 {
1598         int hc, d;
1599         int vc_num = vc->vc_num;
1600         if (count_highlight_color(vc) == 1)
1601                 return 0;
1602         hc = get_highlight_color(vc);
1603         if (hc != -1) {
1604                 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1605                 if ((d == 1) || (d == -1))
1606                         if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1607                                 return 0;
1608                 spk_parked |= 0x01;
1609                 do_flush();
1610                 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1611                             speakup_console[vc_num]->ht.highsize[hc]);
1612                 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1613                 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1614                 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1615                 return 1;
1616         }
1617         return 0;
1618 }
1619
1620 static void cursor_done(u_long data)
1621 {
1622         struct vc_data *vc = vc_cons[cursor_con].d;
1623         unsigned long flags;
1624         del_timer(&cursor_timer);
1625         spk_lock(flags);
1626         if (cursor_con != fg_console) {
1627                 is_cursor = 0;
1628                 goto out;
1629         }
1630         speakup_date(vc);
1631         if (win_enabled) {
1632                 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1633                     vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1634                         spk_keydown = is_cursor = 0;
1635                         goto out;
1636                 }
1637         }
1638         if (cursor_track == read_all_mode) {
1639                 handle_cursor_read_all(vc, read_all_key);
1640                 goto out;
1641         }
1642         if (cursor_track == CT_Highlight) {
1643                 if (speak_highlight(vc)) {
1644                         spk_keydown = is_cursor = 0;
1645                         goto out;
1646                 }
1647         }
1648         if (cursor_track == CT_Window)
1649                 speakup_win_say(vc);
1650         else if (is_cursor == 1 || is_cursor == 4)
1651                 say_line_from_to(vc, 0, vc->vc_cols, 0);
1652         else
1653                 say_char(vc);
1654         spk_keydown = is_cursor = 0;
1655 out:
1656         spk_unlock(flags);
1657 }
1658
1659 /* called by: vt_notifier_call() */
1660 static void speakup_bs(struct vc_data *vc)
1661 {
1662         unsigned long flags;
1663         if (!speakup_console[vc->vc_num])
1664                 return;
1665         if (!spk_trylock(flags))
1666                 /* Speakup output, discard */
1667                 return;
1668         if (!spk_parked)
1669                 speakup_date(vc);
1670         if (spk_shut_up || synth == NULL) {
1671                 spk_unlock(flags);
1672                 return;
1673         }
1674         if (vc->vc_num == fg_console && spk_keydown) {
1675                 spk_keydown = 0;
1676                 if (!is_cursor)
1677                         say_char(vc);
1678         }
1679         spk_unlock(flags);
1680 }
1681
1682 /* called by: vt_notifier_call() */
1683 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1684 {
1685         unsigned long flags;
1686         if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1687                 return;
1688         if (!spk_trylock(flags))
1689                 /* Speakup output, discard */
1690                 return;
1691         if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1))
1692                 bleep(3);
1693         if ((is_cursor) || (cursor_track == read_all_mode)) {
1694                 if (cursor_track == CT_Highlight)
1695                         update_color_buffer(vc, str, len);
1696                 spk_unlock(flags);
1697                 return;
1698         }
1699         if (win_enabled) {
1700                 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1701                     vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1702                         spk_unlock(flags);
1703                         return;
1704                 }
1705         }
1706
1707         spkup_write(str, len);
1708         spk_unlock(flags);
1709 }
1710
1711 void speakup_con_update(struct vc_data *vc)
1712 {
1713         unsigned long flags;
1714         if (speakup_console[vc->vc_num] == NULL || spk_parked)
1715                 return;
1716         if (!spk_trylock(flags))
1717                 /* Speakup output, discard */
1718                 return;
1719         speakup_date(vc);
1720         spk_unlock(flags);
1721 }
1722
1723 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1724 {
1725         unsigned long flags;
1726         int on_off = 2;
1727         char *label;
1728         if (synth == NULL || up_flag || spk_killed)
1729                 return;
1730         spk_lock(flags);
1731         spk_shut_up &= 0xfe;
1732         if (no_intr)
1733                 do_flush();
1734         switch (value) {
1735         case KVAL(K_CAPS):
1736                 label = msg_get(MSG_KEYNAME_CAPSLOCK);
1737                 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
1738                 break;
1739         case KVAL(K_NUM):
1740                 label = msg_get(MSG_KEYNAME_NUMLOCK);
1741                 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
1742                 break;
1743         case KVAL(K_HOLD):
1744                 label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1745                 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK));
1746                 if (speakup_console[vc->vc_num])
1747                         speakup_console[vc->vc_num]->tty_stopped = on_off;
1748                 break;
1749         default:
1750                 spk_parked &= 0xfe;
1751                 spk_unlock(flags);
1752                 return;
1753         }
1754         if (on_off < 2)
1755                 synth_printf("%s %s\n",
1756                              label, msg_get(MSG_STATUS_START + on_off));
1757         spk_unlock(flags);
1758 }
1759
1760 static int inc_dec_var(u_char value)
1761 {
1762         struct st_var_header *p_header;
1763         struct var_t *var_data;
1764         char num_buf[32];
1765         char *cp = num_buf;
1766         char *pn;
1767         int var_id = (int)value - VAR_START;
1768         int how = (var_id & 1) ? E_INC : E_DEC;
1769         var_id = var_id / 2 + FIRST_SET_VAR;
1770         p_header = get_var_header(var_id);
1771         if (p_header == NULL)
1772                 return -1;
1773         if (p_header->var_type != VAR_NUM)
1774                 return -1;
1775         var_data = p_header->data;
1776         if (set_num_var(1, p_header, how) != 0)
1777                 return -1;
1778         if (!spk_close_press) {
1779                 for (pn = p_header->name; *pn; pn++) {
1780                         if (*pn == '_')
1781                                 *cp = SPACE;
1782                         else
1783                                 *cp++ = *pn;
1784                 }
1785         }
1786         snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1787                  var_data->u.n.value);
1788         synth_printf("%s", num_buf);
1789         return 0;
1790 }
1791
1792 static void speakup_win_set(struct vc_data *vc)
1793 {
1794         char info[40];
1795         if (win_start > 1) {
1796                 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1797                 return;
1798         }
1799         if (spk_x < win_left || spk_y < win_top) {
1800                 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1801                 return;
1802         }
1803         if (win_start && spk_x == win_left && spk_y == win_top) {
1804                 win_left = 0;
1805                 win_right = vc->vc_cols - 1;
1806                 win_bottom = spk_y;
1807                 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_LINE),
1808                          (int)win_top + 1);
1809         } else {
1810                 if (!win_start) {
1811                         win_top = spk_y;
1812                         win_left = spk_x;
1813                 } else {
1814                         win_bottom = spk_y;
1815                         win_right = spk_x;
1816                 }
1817                 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1818                          (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1819                          (int)spk_y + 1, (int)spk_x + 1);
1820         }
1821         synth_printf("%s\n", info);
1822         win_start++;
1823 }
1824
1825 static void speakup_win_clear(struct vc_data *vc)
1826 {
1827         win_top = win_bottom = 0;
1828         win_left = win_right = 0;
1829         win_start = 0;
1830         synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1831 }
1832
1833 static void speakup_win_enable(struct vc_data *vc)
1834 {
1835         if (win_start < 2) {
1836                 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1837                 return;
1838         }
1839         win_enabled ^= 1;
1840         if (win_enabled)
1841                 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1842         else
1843                 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1844 }
1845
1846 static void speakup_bits(struct vc_data *vc)
1847 {
1848         int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1849         if (special_handler != NULL || val < 1 || val > 6) {
1850                 synth_printf("%s\n", msg_get(MSG_ERROR));
1851                 return;
1852         }
1853         pb_edit = &punc_info[val];
1854         synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1855         special_handler = edit_bits;
1856 }
1857
1858 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1859 {
1860         static u_char *goto_buf = "\0\0\0\0\0\0";
1861         static int num;
1862         int maxlen, go_pos;
1863         char *cp;
1864         if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1865                 goto do_goto;
1866         if (type == KT_LATIN && ch == '\n')
1867                 goto do_goto;
1868         if (type != 0)
1869                 goto oops;
1870         if (ch == 8) {
1871                 if (num == 0)
1872                         return -1;
1873                 ch = goto_buf[--num];
1874                 goto_buf[num] = '\0';
1875                 spkup_write(&ch, 1);
1876                 return 1;
1877         }
1878         if (ch < '+' || ch > 'y')
1879                 goto oops;
1880         goto_buf[num++] = ch;
1881         goto_buf[num] = '\0';
1882         spkup_write(&ch, 1);
1883         maxlen = (*goto_buf >= '0') ? 3 : 4;
1884         if ((ch == '+' || ch == '-') && num == 1)
1885                 return 1;
1886         if (ch >= '0' && ch <= '9' && num < maxlen)
1887                 return 1;
1888         if (num < maxlen - 1 || num > maxlen)
1889                 goto oops;
1890         if (ch < 'x' || ch > 'y') {
1891 oops:
1892                 if (!spk_killed)
1893                         synth_printf(" %s\n", msg_get(MSG_GOTO_CANCELED));
1894                 goto_buf[num = 0] = '\0';
1895                 special_handler = NULL;
1896                 return 1;
1897         }
1898         cp = speakup_s2i(goto_buf, &go_pos);
1899         goto_pos = (u_long) go_pos;
1900         if (*cp == 'x') {
1901                 if (*goto_buf < '0')
1902                         goto_pos += spk_x;
1903                 else
1904                         goto_pos--;
1905                 if (goto_pos < 0)
1906                         goto_pos = 0;
1907                 if (goto_pos >= vc->vc_cols)
1908                         goto_pos = vc->vc_cols - 1;
1909                 goto_x = 1;
1910         } else {
1911                 if (*goto_buf < '0')
1912                         goto_pos += spk_y;
1913                 else
1914                         goto_pos--;
1915                 if (goto_pos < 0)
1916                         goto_pos = 0;
1917                 if (goto_pos >= vc->vc_rows)
1918                         goto_pos = vc->vc_rows - 1;
1919                 goto_x = 0;
1920         }
1921         goto_buf[num = 0] = '\0';
1922 do_goto:
1923         special_handler = NULL;
1924         spk_parked |= 0x01;
1925         if (goto_x) {
1926                 spk_pos -= spk_x * 2;
1927                 spk_x = goto_pos;
1928                 spk_pos += goto_pos * 2;
1929                 say_word(vc);
1930         } else {
1931                 spk_y = goto_pos;
1932                 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1933                 say_line(vc);
1934         }
1935         return 1;
1936 }
1937
1938 static void speakup_goto(struct vc_data *vc)
1939 {
1940         if (special_handler != NULL) {
1941                 synth_printf("%s\n", msg_get(MSG_ERROR));
1942                 return;
1943         }
1944         synth_printf("%s\n", msg_get(MSG_GOTO));
1945         special_handler = handle_goto;
1946         return;
1947 }
1948
1949 static void speakup_help(struct vc_data *vc)
1950 {
1951         handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1952 }
1953
1954 static void do_nothing(struct vc_data *vc)
1955 {
1956         return;                 /* flush done in do_spkup */
1957 }
1958
1959 static u_char key_speakup, spk_key_locked;
1960
1961 static void speakup_lock(struct vc_data *vc)
1962 {
1963         if (!spk_key_locked)
1964                 spk_key_locked = key_speakup = 16;
1965         else
1966                 spk_key_locked = key_speakup = 0;
1967 }
1968
1969 typedef void (*spkup_hand) (struct vc_data *);
1970 spkup_hand spkup_handler[] = {
1971         /* must be ordered same as defines in speakup.h */
1972         do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1973         speakup_cut, speakup_paste, say_first_char, say_last_char,
1974         say_char, say_prev_char, say_next_char,
1975         say_word, say_prev_word, say_next_word,
1976         say_line, say_prev_line, say_next_line,
1977         top_edge, bottom_edge, left_edge, right_edge,
1978         spell_word, spell_word, say_screen,
1979         say_position, say_attributes,
1980         speakup_off, speakup_parked, say_line,  /* this is for indent */
1981         say_from_top, say_to_bottom,
1982         say_from_left, say_to_right,
1983         say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1984         speakup_bits, speakup_bits, speakup_bits,
1985         speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1986         speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1987 };
1988
1989 static void do_spkup(struct vc_data *vc, u_char value)
1990 {
1991         if (spk_killed && value != SPEECH_KILL)
1992                 return;
1993         spk_keydown = 0;
1994         spk_lastkey = 0;
1995         spk_shut_up &= 0xfe;
1996         this_speakup_key = value;
1997         if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1998                 do_flush();
1999                 (*spkup_handler[value]) (vc);
2000         } else {
2001                 if (inc_dec_var(value) < 0)
2002                         bleep(9);
2003         }
2004 }
2005
2006 static const char *pad_chars = "0123456789+-*/\015,.?()";
2007
2008 int
2009 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2010             int up_flag)
2011 {
2012         unsigned long flags;
2013         int kh;
2014         u_char *key_info;
2015         u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2016         u_char shift_info, offset;
2017         int ret = 0;
2018         if (synth == NULL)
2019                 return 0;
2020
2021         spk_lock(flags);
2022         tty = vc->port.tty;
2023         if (type >= 0xf0)
2024                 type -= 0xf0;
2025         if (type == KT_PAD
2026                 && (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
2027                 if (up_flag) {
2028                         spk_keydown = 0;
2029                         goto out;
2030                 }
2031                 value = spk_lastkey = pad_chars[value];
2032                 spk_keydown++;
2033                 spk_parked &= 0xfe;
2034                 goto no_map;
2035         }
2036         if (keycode >= MAX_KEY)
2037                 goto no_map;
2038         key_info = our_keys[keycode];
2039         if (key_info == 0)
2040                 goto no_map;
2041         /* Check valid read all mode keys */
2042         if ((cursor_track == read_all_mode) && (!up_flag)) {
2043                 switch (value) {
2044                 case KVAL(K_DOWN):
2045                 case KVAL(K_UP):
2046                 case KVAL(K_LEFT):
2047                 case KVAL(K_RIGHT):
2048                 case KVAL(K_PGUP):
2049                 case KVAL(K_PGDN):
2050                         break;
2051                 default:
2052                         stop_read_all(vc);
2053                         break;
2054                 }
2055         }
2056         shift_info = (shift_state & 0x0f) + key_speakup;
2057         offset = shift_table[shift_info];
2058         if (offset) {
2059                 new_key = key_info[offset];
2060                 if (new_key) {
2061                         ret = 1;
2062                         if (new_key == SPK_KEY) {
2063                                 if (!spk_key_locked)
2064                                         key_speakup = (up_flag) ? 0 : 16;
2065                                 if (up_flag || spk_killed)
2066                                         goto out;
2067                                 spk_shut_up &= 0xfe;
2068                                 do_flush();
2069                                 goto out;
2070                         }
2071                         if (up_flag)
2072                                 goto out;
2073                         if (last_keycode == keycode &&
2074                             last_spk_jiffy + MAX_DELAY > jiffies) {
2075                                 spk_close_press = 1;
2076                                 offset = shift_table[shift_info + 32];
2077                                 /* double press? */
2078                                 if (offset && key_info[offset])
2079                                         new_key = key_info[offset];
2080                         }
2081                         last_keycode = keycode;
2082                         last_spk_jiffy = jiffies;
2083                         type = KT_SPKUP;
2084                         value = new_key;
2085                 }
2086         }
2087 no_map:
2088         if (type == KT_SPKUP && special_handler == NULL) {
2089                 do_spkup(vc, new_key);
2090                 spk_close_press = 0;
2091                 ret = 1;
2092                 goto out;
2093         }
2094         if (up_flag || spk_killed || type == KT_SHIFT)
2095                 goto out;
2096         spk_shut_up &= 0xfe;
2097         kh = (value == KVAL(K_DOWN))
2098             || (value == KVAL(K_UP))
2099             || (value == KVAL(K_LEFT))
2100             || (value == KVAL(K_RIGHT));
2101         if ((cursor_track != read_all_mode) || !kh)
2102                 if (!no_intr)
2103                         do_flush();
2104         if (special_handler) {
2105                 if (type == KT_SPEC && value == 1) {
2106                         value = '\n';
2107                         type = KT_LATIN;
2108                 } else if (type == KT_LETTER)
2109                         type = KT_LATIN;
2110                 else if (value == 0x7f)
2111                         value = 8;      /* make del = backspace */
2112                 ret = (*special_handler) (vc, type, value, keycode);
2113                 spk_close_press = 0;
2114                 if (ret < 0)
2115                         bleep(9);
2116                 goto out;
2117         }
2118         last_keycode = 0;
2119 out:
2120         spk_unlock(flags);
2121         return ret;
2122 }
2123
2124 static int keyboard_notifier_call(struct notifier_block *nb,
2125                                   unsigned long code, void *_param)
2126 {
2127         struct keyboard_notifier_param *param = _param;
2128         struct vc_data *vc = param->vc;
2129         int up = !param->down;
2130         int ret = NOTIFY_OK;
2131         static int keycode;     /* to hold the current keycode */
2132
2133         if (vc->vc_mode == KD_GRAPHICS)
2134                 return ret;
2135
2136         /*
2137          * First, determine whether we are handling a fake keypress on
2138          * the current processor.  If we are, then return NOTIFY_OK,
2139          * to pass the keystroke up the chain.  This prevents us from
2140          * trying to take the Speakup lock while it is held by the
2141          * processor on which the simulated keystroke was generated.
2142          * Also, the simulated keystrokes should be ignored by Speakup.
2143          */
2144
2145         if (speakup_fake_key_pressed())
2146                 return ret;
2147
2148         switch (code) {
2149         case KBD_KEYCODE:
2150                 /* speakup requires keycode and keysym currently */
2151                 keycode = param->value;
2152                 break;
2153         case KBD_UNBOUND_KEYCODE:
2154                 /* not used yet */
2155                 break;
2156         case KBD_UNICODE:
2157                 /* not used yet */
2158                 break;
2159         case KBD_KEYSYM:
2160                 if (speakup_key(vc, param->shift, keycode, param->value, up))
2161                         ret = NOTIFY_STOP;
2162                 else if (KTYP(param->value) == KT_CUR)
2163                         ret = pre_handle_cursor(vc, KVAL(param->value), up);
2164                 break;
2165         case KBD_POST_KEYSYM:{
2166                         unsigned char type = KTYP(param->value) - 0xf0;
2167                         unsigned char val = KVAL(param->value);
2168                         switch (type) {
2169                         case KT_SHIFT:
2170                                 do_handle_shift(vc, val, up);
2171                                 break;
2172                         case KT_LATIN:
2173                         case KT_LETTER:
2174                                 do_handle_latin(vc, val, up);
2175                                 break;
2176                         case KT_CUR:
2177                                 do_handle_cursor(vc, val, up);
2178                                 break;
2179                         case KT_SPEC:
2180                                 do_handle_spec(vc, val, up);
2181                                 break;
2182                         }
2183                         break;
2184                 }
2185         }
2186         return ret;
2187 }
2188
2189 static int vt_notifier_call(struct notifier_block *nb,
2190                             unsigned long code, void *_param)
2191 {
2192         struct vt_notifier_param *param = _param;
2193         struct vc_data *vc = param->vc;
2194         switch (code) {
2195         case VT_ALLOCATE:
2196                 if (vc->vc_mode == KD_TEXT)
2197                         speakup_allocate(vc);
2198                 break;
2199         case VT_DEALLOCATE:
2200                 speakup_deallocate(vc);
2201                 break;
2202         case VT_WRITE:
2203                 if (param->c == '\b')
2204                         speakup_bs(vc);
2205                 else if (param->c < 0x100) {
2206                         char d = param->c;
2207                         speakup_con_write(vc, &d, 1);
2208                 }
2209                 break;
2210         case VT_UPDATE:
2211                 speakup_con_update(vc);
2212                 break;
2213         }
2214         return NOTIFY_OK;
2215 }
2216
2217 /* called by: module_exit() */
2218 static void __exit speakup_exit(void)
2219 {
2220         int i;
2221
2222         unregister_keyboard_notifier(&keyboard_notifier_block);
2223         unregister_vt_notifier(&vt_notifier_block);
2224         speakup_unregister_devsynth();
2225         del_timer(&cursor_timer);
2226         kthread_stop(speakup_task);
2227         speakup_task = NULL;
2228         mutex_lock(&spk_mutex);
2229         synth_release();
2230         mutex_unlock(&spk_mutex);
2231
2232         speakup_kobj_exit();
2233
2234         for (i = 0; i < MAX_NR_CONSOLES; i++)
2235                 kfree(speakup_console[i]);
2236
2237         speakup_remove_virtual_keyboard();
2238
2239         for (i = 0; i < MAXVARS; i++)
2240                 speakup_unregister_var(i);
2241
2242         for (i = 0; i < 256; i++) {
2243                 if (characters[i] != default_chars[i])
2244                         kfree(characters[i]);
2245         }
2246
2247         free_user_msgs();
2248 }
2249
2250 /* call by: module_init() */
2251 static int __init speakup_init(void)
2252 {
2253         int i;
2254         long err = 0;
2255         struct st_spk_t *first_console;
2256         struct vc_data *vc = vc_cons[fg_console].d;
2257         struct var_t *var;
2258
2259         /* These first few initializations cannot fail. */
2260         initialize_msgs();      /* Initialize arrays for i18n. */
2261         reset_default_chars();
2262         reset_default_chartab();
2263         strlwr(synth_name);
2264         spk_vars[0].u.n.high = vc->vc_cols;
2265         for (var = spk_vars; var->var_id != MAXVARS; var++)
2266                 speakup_register_var(var);
2267         for (var = synth_time_vars;
2268              (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2269                 speakup_register_var(var);
2270         for (i = 1; punc_info[i].mask != 0; i++)
2271                 set_mask_bits(0, i, 2);
2272
2273         set_key_info(key_defaults, key_buf);
2274         if (quiet_boot)
2275                 spk_shut_up |= 0x01;
2276
2277         /* From here on out, initializations can fail. */
2278         err = speakup_add_virtual_keyboard();
2279         if (err)
2280                 goto error_virtkeyboard;
2281
2282         first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2283         if (!first_console) {
2284                 err = -ENOMEM;
2285                 goto error_alloc;
2286         }
2287
2288         speakup_console[vc->vc_num] = first_console;
2289         speakup_date(vc);
2290
2291         for (i = 0; i < MAX_NR_CONSOLES; i++)
2292                 if (vc_cons[i].d) {
2293                         err = speakup_allocate(vc_cons[i].d);
2294                         if (err)
2295                                 goto error_kobjects;
2296                 }
2297
2298         err = speakup_kobj_init();
2299         if (err)
2300                 goto error_kobjects;
2301
2302         synth_init(synth_name);
2303         speakup_register_devsynth();
2304         /*
2305          * register_devsynth might fail, but this error is not fatal.
2306          * /dev/synth is an extra feature; the rest of Speakup
2307          * will work fine without it.
2308          */
2309
2310         err = register_keyboard_notifier(&keyboard_notifier_block);
2311         if (err)
2312                 goto error_kbdnotifier;
2313         err = register_vt_notifier(&vt_notifier_block);
2314         if (err)
2315                 goto error_vtnotifier;
2316
2317         speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2318
2319         if (IS_ERR(speakup_task)) {
2320                 err = PTR_ERR(speakup_task);
2321                 goto error_task;
2322         }
2323
2324         set_user_nice(speakup_task, 10);
2325         wake_up_process(speakup_task);
2326
2327         pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2328         pr_info("synth name on entry is: %s\n", synth_name);
2329         goto out;
2330
2331 error_task:
2332         unregister_vt_notifier(&vt_notifier_block);
2333
2334 error_vtnotifier:
2335         unregister_keyboard_notifier(&keyboard_notifier_block);
2336         del_timer(&cursor_timer);
2337
2338 error_kbdnotifier:
2339         speakup_unregister_devsynth();
2340         mutex_lock(&spk_mutex);
2341         synth_release();
2342         mutex_unlock(&spk_mutex);
2343         speakup_kobj_exit();
2344
2345 error_kobjects:
2346         for (i = 0; i < MAX_NR_CONSOLES; i++)
2347                 kfree(speakup_console[i]);
2348
2349 error_alloc:
2350         speakup_remove_virtual_keyboard();
2351
2352 error_virtkeyboard:
2353         for (i = 0; i < MAXVARS; i++)
2354                 speakup_unregister_var(i);
2355
2356         for (i = 0; i < 256; i++) {
2357                 if (characters[i] != default_chars[i])
2358                         kfree(characters[i]);
2359         }
2360
2361         free_user_msgs();
2362
2363 out:
2364         return err;
2365 }
2366
2367 module_init(speakup_init);
2368 module_exit(speakup_exit);