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