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