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