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