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