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