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