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