Merge branch 'drm-tda998x-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into...
[deliverable/linux.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(u16 *pos)
268 {
269 return (u_char) (scr_readw(pos) >> 8);
270 }
271
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
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
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
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
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
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
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
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
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
423 static void announce_edge(struct vc_data *vc, int msg_id)
424 {
425 if (spk_bleeps & 1)
426 bleep(spk_y);
427 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
428 synth_printf("%s\n",
429 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
430 }
431
432 static void speak_char(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
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
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
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
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
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
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) >
566 SPACE)) {
567 tmp_pos += 2;
568 tmpx++;
569 } else
570 while (tmpx > 0) {
571 ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
572 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
573 && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
574 SPACE))
575 break;
576 tmp_pos -= 2;
577 tmpx--;
578 }
579 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
580 buf[cnt++] = attr_ch & 0xff;
581 while (tmpx < vc->vc_cols - 1) {
582 tmp_pos += 2;
583 tmpx++;
584 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
585 if ((ch == SPACE) || ch == 0
586 || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
587 break;
588 buf[cnt++] = ch;
589 }
590 buf[cnt] = '\0';
591 return cnt;
592 }
593
594 static void say_word(struct vc_data *vc)
595 {
596 u_long cnt = get_word(vc);
597 u_short saved_punc_mask = spk_punc_mask;
598
599 if (cnt == 0)
600 return;
601 spk_punc_mask = PUNC;
602 buf[cnt++] = SPACE;
603 spkup_write(buf, cnt);
604 spk_punc_mask = saved_punc_mask;
605 }
606
607 static void say_prev_word(struct vc_data *vc)
608 {
609 u_char temp;
610 char ch;
611 u_short edge_said = 0, last_state = 0, state = 0;
612
613 spk_parked |= 0x01;
614
615 if (spk_x == 0) {
616 if (spk_y == 0) {
617 announce_edge(vc, edge_top);
618 return;
619 }
620 spk_y--;
621 spk_x = vc->vc_cols;
622 edge_said = edge_quiet;
623 }
624 while (1) {
625 if (spk_x == 0) {
626 if (spk_y == 0) {
627 edge_said = edge_top;
628 break;
629 }
630 if (edge_said != edge_quiet)
631 edge_said = edge_left;
632 if (state > 0)
633 break;
634 spk_y--;
635 spk_x = vc->vc_cols - 1;
636 } else
637 spk_x--;
638 spk_pos -= 2;
639 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
640 if (ch == SPACE || ch == 0)
641 state = 0;
642 else if (IS_WDLM(ch))
643 state = 1;
644 else
645 state = 2;
646 if (state < last_state) {
647 spk_pos += 2;
648 spk_x++;
649 break;
650 }
651 last_state = state;
652 }
653 if (spk_x == 0 && edge_said == edge_quiet)
654 edge_said = edge_left;
655 if (edge_said > 0 && edge_said < edge_quiet)
656 announce_edge(vc, edge_said);
657 say_word(vc);
658 }
659
660 static void say_next_word(struct vc_data *vc)
661 {
662 u_char temp;
663 char ch;
664 u_short edge_said = 0, last_state = 2, state = 0;
665
666 spk_parked |= 0x01;
667 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
668 announce_edge(vc, edge_bottom);
669 return;
670 }
671 while (1) {
672 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
673 if (ch == SPACE || ch == 0)
674 state = 0;
675 else if (IS_WDLM(ch))
676 state = 1;
677 else
678 state = 2;
679 if (state > last_state)
680 break;
681 if (spk_x >= vc->vc_cols - 1) {
682 if (spk_y == vc->vc_rows - 1) {
683 edge_said = edge_bottom;
684 break;
685 }
686 state = 0;
687 spk_y++;
688 spk_x = 0;
689 edge_said = edge_right;
690 } else
691 spk_x++;
692 spk_pos += 2;
693 last_state = state;
694 }
695 if (edge_said > 0)
696 announce_edge(vc, edge_said);
697 say_word(vc);
698 }
699
700 static void spell_word(struct vc_data *vc)
701 {
702 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
703 char *cp = buf, *str_cap = spk_str_caps_stop;
704 char *cp1, *last_cap = spk_str_caps_stop;
705 u_char ch;
706
707 if (!get_word(vc))
708 return;
709 while ((ch = (u_char) *cp)) {
710 if (cp != buf)
711 synth_printf(" %s ", delay_str[spk_spell_delay]);
712 if (IS_CHAR(ch, B_CAP)) {
713 str_cap = spk_str_caps_start;
714 if (*spk_str_caps_stop)
715 spk_pitch_shift++;
716 else /* synth has no pitch */
717 last_cap = spk_str_caps_stop;
718 } else
719 str_cap = spk_str_caps_stop;
720 if (str_cap != last_cap) {
721 synth_printf("%s", str_cap);
722 last_cap = str_cap;
723 }
724 if (this_speakup_key == SPELL_PHONETIC
725 && (isascii(ch) && isalpha(ch))) {
726 ch &= 31;
727 cp1 = phonetic[--ch];
728 } else {
729 cp1 = spk_characters[ch];
730 if (*cp1 == '^') {
731 synth_printf("%s", spk_msg_get(MSG_CTRL));
732 cp1++;
733 }
734 }
735 synth_printf("%s", cp1);
736 cp++;
737 }
738 if (str_cap != spk_str_caps_stop)
739 synth_printf("%s", spk_str_caps_stop);
740 }
741
742 static int get_line(struct vc_data *vc)
743 {
744 u_long tmp = spk_pos - (spk_x * 2);
745 int i = 0;
746 u_char tmp2;
747
748 spk_old_attr = spk_attr;
749 spk_attr = get_attributes((u_short *) spk_pos);
750 for (i = 0; i < vc->vc_cols; i++) {
751 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
752 tmp += 2;
753 }
754 for (--i; i >= 0; i--)
755 if (buf[i] != SPACE)
756 break;
757 return ++i;
758 }
759
760 static void say_line(struct vc_data *vc)
761 {
762 int i = get_line(vc);
763 char *cp;
764 u_short saved_punc_mask = spk_punc_mask;
765
766 if (i == 0) {
767 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
768 return;
769 }
770 buf[i++] = '\n';
771 if (this_speakup_key == SAY_LINE_INDENT) {
772 cp = buf;
773 while (*cp == SPACE)
774 cp++;
775 synth_printf("%d, ", (cp - buf) + 1);
776 }
777 spk_punc_mask = spk_punc_masks[spk_reading_punc];
778 spkup_write(buf, i);
779 spk_punc_mask = saved_punc_mask;
780 }
781
782 static void say_prev_line(struct vc_data *vc)
783 {
784 spk_parked |= 0x01;
785 if (spk_y == 0) {
786 announce_edge(vc, edge_top);
787 return;
788 }
789 spk_y--;
790 spk_pos -= vc->vc_size_row;
791 say_line(vc);
792 }
793
794 static void say_next_line(struct vc_data *vc)
795 {
796 spk_parked |= 0x01;
797 if (spk_y == vc->vc_rows - 1) {
798 announce_edge(vc, edge_bottom);
799 return;
800 }
801 spk_y++;
802 spk_pos += vc->vc_size_row;
803 say_line(vc);
804 }
805
806 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
807 int read_punc)
808 {
809 int i = 0;
810 u_char tmp;
811 u_short saved_punc_mask = spk_punc_mask;
812
813 spk_old_attr = spk_attr;
814 spk_attr = get_attributes((u_short *) from);
815 while (from < to) {
816 buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
817 from += 2;
818 if (i >= vc->vc_size_row)
819 break;
820 }
821 for (--i; i >= 0; i--)
822 if (buf[i] != SPACE)
823 break;
824 buf[++i] = SPACE;
825 buf[++i] = '\0';
826 if (i < 1)
827 return i;
828 if (read_punc)
829 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
830 spkup_write(buf, i);
831 if (read_punc)
832 spk_punc_mask = saved_punc_mask;
833 return i - 1;
834 }
835
836 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
837 int read_punc)
838 {
839 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
840 u_long end = start + (to * 2);
841
842 start += from * 2;
843 if (say_from_to(vc, start, end, read_punc) <= 0)
844 if (cursor_track != read_all_mode)
845 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
846 }
847
848 /* Sentence Reading Commands */
849
850 static int currsentence;
851 static int numsentences[2];
852 static char *sentbufend[2];
853 static char *sentmarks[2][10];
854 static int currbuf;
855 static int bn;
856 static char sentbuf[2][256];
857
858 static int say_sentence_num(int num, int prev)
859 {
860 bn = currbuf;
861 currsentence = num + 1;
862 if (prev && --bn == -1)
863 bn = 1;
864
865 if (num > numsentences[bn])
866 return 0;
867
868 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
869 return 1;
870 }
871
872 static int get_sentence_buf(struct vc_data *vc, int read_punc)
873 {
874 u_long start, end;
875 int i, bn;
876 u_char tmp;
877
878 currbuf++;
879 if (currbuf == 2)
880 currbuf = 0;
881 bn = currbuf;
882 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
883 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
884
885 numsentences[bn] = 0;
886 sentmarks[bn][0] = &sentbuf[bn][0];
887 i = 0;
888 spk_old_attr = spk_attr;
889 spk_attr = get_attributes((u_short *) start);
890
891 while (start < end) {
892 sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
893 if (i > 0) {
894 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
895 && numsentences[bn] < 9) {
896 /* Sentence Marker */
897 numsentences[bn]++;
898 sentmarks[bn][numsentences[bn]] =
899 &sentbuf[bn][i];
900 }
901 }
902 i++;
903 start += 2;
904 if (i >= vc->vc_size_row)
905 break;
906 }
907
908 for (--i; i >= 0; i--)
909 if (sentbuf[bn][i] != SPACE)
910 break;
911
912 if (i < 1)
913 return -1;
914
915 sentbuf[bn][++i] = SPACE;
916 sentbuf[bn][++i] = '\0';
917
918 sentbufend[bn] = &sentbuf[bn][i];
919 return numsentences[bn];
920 }
921
922 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
923 {
924 u_long start = vc->vc_origin, end;
925
926 if (from > 0)
927 start += from * vc->vc_size_row;
928 if (to > vc->vc_rows)
929 to = vc->vc_rows;
930 end = vc->vc_origin + (to * vc->vc_size_row);
931 for (from = start; from < end; from = to) {
932 to = from + vc->vc_size_row;
933 say_from_to(vc, from, to, 1);
934 }
935 }
936
937 static void say_screen(struct vc_data *vc)
938 {
939 say_screen_from_to(vc, 0, vc->vc_rows);
940 }
941
942 static void speakup_win_say(struct vc_data *vc)
943 {
944 u_long start, end, from, to;
945
946 if (win_start < 2) {
947 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
948 return;
949 }
950 start = vc->vc_origin + (win_top * vc->vc_size_row);
951 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
952 while (start <= end) {
953 from = start + (win_left * 2);
954 to = start + (win_right * 2);
955 say_from_to(vc, from, to, 1);
956 start += vc->vc_size_row;
957 }
958 }
959
960 static void top_edge(struct vc_data *vc)
961 {
962 spk_parked |= 0x01;
963 spk_pos = vc->vc_origin + 2 * spk_x;
964 spk_y = 0;
965 say_line(vc);
966 }
967
968 static void bottom_edge(struct vc_data *vc)
969 {
970 spk_parked |= 0x01;
971 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
972 spk_y = vc->vc_rows - 1;
973 say_line(vc);
974 }
975
976 static void left_edge(struct vc_data *vc)
977 {
978 spk_parked |= 0x01;
979 spk_pos -= spk_x * 2;
980 spk_x = 0;
981 say_char(vc);
982 }
983
984 static void right_edge(struct vc_data *vc)
985 {
986 spk_parked |= 0x01;
987 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
988 spk_x = vc->vc_cols - 1;
989 say_char(vc);
990 }
991
992 static void say_first_char(struct vc_data *vc)
993 {
994 int i, len = get_line(vc);
995 u_char ch;
996
997 spk_parked |= 0x01;
998 if (len == 0) {
999 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1000 return;
1001 }
1002 for (i = 0; i < len; i++)
1003 if (buf[i] != SPACE)
1004 break;
1005 ch = buf[i];
1006 spk_pos -= (spk_x - i) * 2;
1007 spk_x = i;
1008 synth_printf("%d, ", ++i);
1009 speak_char(ch);
1010 }
1011
1012 static void say_last_char(struct vc_data *vc)
1013 {
1014 int len = get_line(vc);
1015 u_char ch;
1016
1017 spk_parked |= 0x01;
1018 if (len == 0) {
1019 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1020 return;
1021 }
1022 ch = buf[--len];
1023 spk_pos -= (spk_x - len) * 2;
1024 spk_x = len;
1025 synth_printf("%d, ", ++len);
1026 speak_char(ch);
1027 }
1028
1029 static void say_position(struct vc_data *vc)
1030 {
1031 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1032 vc->vc_num + 1);
1033 synth_printf("\n");
1034 }
1035
1036 /* Added by brianb */
1037 static void say_char_num(struct vc_data *vc)
1038 {
1039 u_char tmp;
1040 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1041
1042 ch &= 0xff;
1043 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1044 }
1045
1046 /* these are stub functions to keep keyboard.c happy. */
1047
1048 static void say_from_top(struct vc_data *vc)
1049 {
1050 say_screen_from_to(vc, 0, spk_y);
1051 }
1052
1053 static void say_to_bottom(struct vc_data *vc)
1054 {
1055 say_screen_from_to(vc, spk_y, vc->vc_rows);
1056 }
1057
1058 static void say_from_left(struct vc_data *vc)
1059 {
1060 say_line_from_to(vc, 0, spk_x, 1);
1061 }
1062
1063 static void say_to_right(struct vc_data *vc)
1064 {
1065 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1066 }
1067
1068 /* end of stub functions. */
1069
1070 static void spkup_write(const char *in_buf, int count)
1071 {
1072 static int rep_count;
1073 static u_char ch = '\0', old_ch = '\0';
1074 static u_short char_type, last_type;
1075 int in_count = count;
1076
1077 spk_keydown = 0;
1078 while (count--) {
1079 if (cursor_track == read_all_mode) {
1080 /* Insert Sentence Index */
1081 if ((in_buf == sentmarks[bn][currsentence]) &&
1082 (currsentence <= numsentences[bn]))
1083 synth_insert_next_index(currsentence++);
1084 }
1085 ch = (u_char) *in_buf++;
1086 char_type = spk_chartab[ch];
1087 if (ch == old_ch && !(char_type & B_NUM)) {
1088 if (++rep_count > 2)
1089 continue;
1090 } else {
1091 if ((last_type & CH_RPT) && rep_count > 2) {
1092 synth_printf(" ");
1093 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1094 ++rep_count);
1095 synth_printf(" ");
1096 }
1097 rep_count = 0;
1098 }
1099 if (ch == spk_lastkey) {
1100 rep_count = 0;
1101 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1102 speak_char(ch);
1103 } else if (char_type & B_ALPHA) {
1104 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1105 synth_buffer_add(SPACE);
1106 synth_printf("%c", ch);
1107 } else if (char_type & B_NUM) {
1108 rep_count = 0;
1109 synth_printf("%c", ch);
1110 } else if (char_type & spk_punc_mask) {
1111 speak_char(ch);
1112 char_type &= ~PUNC; /* for dec nospell processing */
1113 } else if (char_type & SYNTH_OK) {
1114 /* these are usually puncts like . and , which synth
1115 * needs for expression.
1116 * suppress multiple to get rid of long pauses and
1117 * clear repeat count
1118 * so if someone has
1119 * repeats on you don't get nothing repeated count
1120 */
1121 if (ch != old_ch)
1122 synth_printf("%c", ch);
1123 else
1124 rep_count = 0;
1125 } else {
1126 /* send space and record position, if next is num overwrite space */
1127 if (old_ch != ch)
1128 synth_buffer_add(SPACE);
1129 else
1130 rep_count = 0;
1131 }
1132 old_ch = ch;
1133 last_type = char_type;
1134 }
1135 spk_lastkey = 0;
1136 if (in_count > 2 && rep_count > 2) {
1137 if (last_type & CH_RPT) {
1138 synth_printf(" ");
1139 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1140 ++rep_count);
1141 synth_printf(" ");
1142 }
1143 rep_count = 0;
1144 }
1145 }
1146
1147 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1148
1149 static void read_all_doc(struct vc_data *vc);
1150 static void cursor_done(u_long data);
1151 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1152
1153 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1154 {
1155 unsigned long flags;
1156
1157 if (synth == NULL || up_flag || spk_killed)
1158 return;
1159 spin_lock_irqsave(&speakup_info.spinlock, flags);
1160 if (cursor_track == read_all_mode) {
1161 switch (value) {
1162 case KVAL(K_SHIFT):
1163 del_timer(&cursor_timer);
1164 spk_shut_up &= 0xfe;
1165 spk_do_flush();
1166 read_all_doc(vc);
1167 break;
1168 case KVAL(K_CTRL):
1169 del_timer(&cursor_timer);
1170 cursor_track = prev_cursor_track;
1171 spk_shut_up &= 0xfe;
1172 spk_do_flush();
1173 break;
1174 }
1175 } else {
1176 spk_shut_up &= 0xfe;
1177 spk_do_flush();
1178 }
1179 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1180 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1181 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1182 }
1183
1184 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1185 {
1186 unsigned long flags;
1187
1188 spin_lock_irqsave(&speakup_info.spinlock, flags);
1189 if (up_flag) {
1190 spk_lastkey = spk_keydown = 0;
1191 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1192 return;
1193 }
1194 if (synth == NULL || spk_killed) {
1195 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1196 return;
1197 }
1198 spk_shut_up &= 0xfe;
1199 spk_lastkey = value;
1200 spk_keydown++;
1201 spk_parked &= 0xfe;
1202 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1203 speak_char(value);
1204 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1205 }
1206
1207 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1208 {
1209 int i = 0, states, key_data_len;
1210 const u_char *cp = key_info;
1211 u_char *cp1 = k_buffer;
1212 u_char ch, version, num_keys;
1213
1214 version = *cp++;
1215 if (version != KEY_MAP_VER)
1216 return -1;
1217 num_keys = *cp;
1218 states = (int)cp[1];
1219 key_data_len = (states + 1) * (num_keys + 1);
1220 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1221 return -2;
1222 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1223 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1224 spk_shift_table = k_buffer;
1225 spk_our_keys[0] = spk_shift_table;
1226 cp1 += SHIFT_TBL_SIZE;
1227 memcpy(cp1, cp, key_data_len + 3);
1228 /* get num_keys, states and data */
1229 cp1 += 2; /* now pointing at shift states */
1230 for (i = 1; i <= states; i++) {
1231 ch = *cp1++;
1232 if (ch >= SHIFT_TBL_SIZE)
1233 return -3;
1234 spk_shift_table[ch] = i;
1235 }
1236 keymap_flags = *cp1++;
1237 while ((ch = *cp1)) {
1238 if (ch >= MAX_KEY)
1239 return -4;
1240 spk_our_keys[ch] = cp1;
1241 cp1 += states + 1;
1242 }
1243 return 0;
1244 }
1245
1246 static struct var_t spk_vars[] = {
1247 /* bell must be first to set high limit */
1248 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1249 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1250 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1251 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1252 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1253 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1254 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1255 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1256 {SAY_CONTROL, TOGGLE_0},
1257 {SAY_WORD_CTL, TOGGLE_0},
1258 {NO_INTERRUPT, TOGGLE_0},
1259 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1260 V_LAST_VAR
1261 };
1262
1263 static void toggle_cursoring(struct vc_data *vc)
1264 {
1265 if (cursor_track == read_all_mode)
1266 cursor_track = prev_cursor_track;
1267 if (++cursor_track >= CT_Max)
1268 cursor_track = 0;
1269 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1270 }
1271
1272 void spk_reset_default_chars(void)
1273 {
1274 int i;
1275
1276 /* First, free any non-default */
1277 for (i = 0; i < 256; i++) {
1278 if ((spk_characters[i] != NULL)
1279 && (spk_characters[i] != spk_default_chars[i]))
1280 kfree(spk_characters[i]);
1281 }
1282
1283 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1284 }
1285
1286 void spk_reset_default_chartab(void)
1287 {
1288 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1289 }
1290
1291 static const struct st_bits_data *pb_edit;
1292
1293 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1294 {
1295 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1296
1297 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1298 return -1;
1299 if (ch == SPACE) {
1300 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1301 spk_special_handler = NULL;
1302 return 1;
1303 }
1304 if (mask < PUNC && !(ch_type & PUNC))
1305 return -1;
1306 spk_chartab[ch] ^= mask;
1307 speak_char(ch);
1308 synth_printf(" %s\n",
1309 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1310 spk_msg_get(MSG_OFF));
1311 return 1;
1312 }
1313
1314 /* Allocation concurrency is protected by the console semaphore */
1315 static int speakup_allocate(struct vc_data *vc)
1316 {
1317 int vc_num;
1318
1319 vc_num = vc->vc_num;
1320 if (speakup_console[vc_num] == NULL) {
1321 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1322 GFP_ATOMIC);
1323 if (speakup_console[vc_num] == NULL)
1324 return -ENOMEM;
1325 speakup_date(vc);
1326 } else if (!spk_parked)
1327 speakup_date(vc);
1328
1329 return 0;
1330 }
1331
1332 static void speakup_deallocate(struct vc_data *vc)
1333 {
1334 int vc_num;
1335
1336 vc_num = vc->vc_num;
1337 kfree(speakup_console[vc_num]);
1338 speakup_console[vc_num] = NULL;
1339 }
1340
1341 static u_char is_cursor;
1342 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1343 static int cursor_con;
1344
1345 static void reset_highlight_buffers(struct vc_data *);
1346
1347 static int read_all_key;
1348
1349 static void start_read_all_timer(struct vc_data *vc, int command);
1350
1351 enum {
1352 RA_NOTHING,
1353 RA_NEXT_SENT,
1354 RA_PREV_LINE,
1355 RA_NEXT_LINE,
1356 RA_PREV_SENT,
1357 RA_DOWN_ARROW,
1358 RA_TIMER,
1359 RA_FIND_NEXT_SENT,
1360 RA_FIND_PREV_SENT,
1361 };
1362
1363 static void kbd_fakekey2(struct vc_data *vc, int command)
1364 {
1365 del_timer(&cursor_timer);
1366 speakup_fake_down_arrow();
1367 start_read_all_timer(vc, command);
1368 }
1369
1370 static void read_all_doc(struct vc_data *vc)
1371 {
1372 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1373 return;
1374 if (!synth_supports_indexing())
1375 return;
1376 if (cursor_track != read_all_mode)
1377 prev_cursor_track = cursor_track;
1378 cursor_track = read_all_mode;
1379 spk_reset_index_count(0);
1380 if (get_sentence_buf(vc, 0) == -1)
1381 kbd_fakekey2(vc, RA_DOWN_ARROW);
1382 else {
1383 say_sentence_num(0, 0);
1384 synth_insert_next_index(0);
1385 start_read_all_timer(vc, RA_TIMER);
1386 }
1387 }
1388
1389 static void stop_read_all(struct vc_data *vc)
1390 {
1391 del_timer(&cursor_timer);
1392 cursor_track = prev_cursor_track;
1393 spk_shut_up &= 0xfe;
1394 spk_do_flush();
1395 }
1396
1397 static void start_read_all_timer(struct vc_data *vc, int command)
1398 {
1399 struct var_t *cursor_timeout;
1400
1401 cursor_con = vc->vc_num;
1402 read_all_key = command;
1403 cursor_timeout = spk_get_var(CURSOR_TIME);
1404 mod_timer(&cursor_timer,
1405 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1406 }
1407
1408 static void handle_cursor_read_all(struct vc_data *vc, int command)
1409 {
1410 int indcount, sentcount, rv, sn;
1411
1412 switch (command) {
1413 case RA_NEXT_SENT:
1414 /* Get Current Sentence */
1415 spk_get_index_count(&indcount, &sentcount);
1416 /*printk("%d %d ", indcount, sentcount); */
1417 spk_reset_index_count(sentcount + 1);
1418 if (indcount == 1) {
1419 if (!say_sentence_num(sentcount + 1, 0)) {
1420 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1421 return;
1422 }
1423 synth_insert_next_index(0);
1424 } else {
1425 sn = 0;
1426 if (!say_sentence_num(sentcount + 1, 1)) {
1427 sn = 1;
1428 spk_reset_index_count(sn);
1429 } else
1430 synth_insert_next_index(0);
1431 if (!say_sentence_num(sn, 0)) {
1432 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1433 return;
1434 }
1435 synth_insert_next_index(0);
1436 }
1437 start_read_all_timer(vc, RA_TIMER);
1438 break;
1439 case RA_PREV_SENT:
1440 break;
1441 case RA_NEXT_LINE:
1442 read_all_doc(vc);
1443 break;
1444 case RA_PREV_LINE:
1445 break;
1446 case RA_DOWN_ARROW:
1447 if (get_sentence_buf(vc, 0) == -1) {
1448 kbd_fakekey2(vc, RA_DOWN_ARROW);
1449 } else {
1450 say_sentence_num(0, 0);
1451 synth_insert_next_index(0);
1452 start_read_all_timer(vc, RA_TIMER);
1453 }
1454 break;
1455 case RA_FIND_NEXT_SENT:
1456 rv = get_sentence_buf(vc, 0);
1457 if (rv == -1)
1458 read_all_doc(vc);
1459 if (rv == 0)
1460 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1461 else {
1462 say_sentence_num(1, 0);
1463 synth_insert_next_index(0);
1464 start_read_all_timer(vc, RA_TIMER);
1465 }
1466 break;
1467 case RA_FIND_PREV_SENT:
1468 break;
1469 case RA_TIMER:
1470 spk_get_index_count(&indcount, &sentcount);
1471 if (indcount < 2)
1472 kbd_fakekey2(vc, RA_DOWN_ARROW);
1473 else
1474 start_read_all_timer(vc, RA_TIMER);
1475 break;
1476 }
1477 }
1478
1479 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1480 {
1481 unsigned long flags;
1482
1483 spin_lock_irqsave(&speakup_info.spinlock, flags);
1484 if (cursor_track == read_all_mode) {
1485 spk_parked &= 0xfe;
1486 if (synth == NULL || up_flag || spk_shut_up) {
1487 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1488 return NOTIFY_STOP;
1489 }
1490 del_timer(&cursor_timer);
1491 spk_shut_up &= 0xfe;
1492 spk_do_flush();
1493 start_read_all_timer(vc, value + 1);
1494 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1495 return NOTIFY_STOP;
1496 }
1497 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1498 return NOTIFY_OK;
1499 }
1500
1501 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1502 {
1503 unsigned long flags;
1504 struct var_t *cursor_timeout;
1505
1506 spin_lock_irqsave(&speakup_info.spinlock, flags);
1507 spk_parked &= 0xfe;
1508 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1509 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1510 return;
1511 }
1512 spk_shut_up &= 0xfe;
1513 if (spk_no_intr)
1514 spk_do_flush();
1515 /* the key press flushes if !no_inter but we want to flush on cursor
1516 * moves regardless of no_inter state
1517 */
1518 is_cursor = value + 1;
1519 old_cursor_pos = vc->vc_pos;
1520 old_cursor_x = vc->vc_x;
1521 old_cursor_y = vc->vc_y;
1522 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1523 cursor_con = vc->vc_num;
1524 if (cursor_track == CT_Highlight)
1525 reset_highlight_buffers(vc);
1526 cursor_timeout = spk_get_var(CURSOR_TIME);
1527 mod_timer(&cursor_timer,
1528 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1529 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1530 }
1531
1532 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1533 {
1534 int i, bi, hi;
1535 int vc_num = vc->vc_num;
1536
1537 bi = (vc->vc_attr & 0x70) >> 4;
1538 hi = speakup_console[vc_num]->ht.highsize[bi];
1539
1540 i = 0;
1541 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1542 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1543 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1544 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1545 }
1546 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1547 if ((ic[i] > 32) && (ic[i] < 127)) {
1548 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1549 hi++;
1550 } else if ((ic[i] == 32) && (hi != 0)) {
1551 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1552 32) {
1553 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1554 ic[i];
1555 hi++;
1556 }
1557 }
1558 i++;
1559 }
1560 speakup_console[vc_num]->ht.highsize[bi] = hi;
1561 }
1562
1563 static void reset_highlight_buffers(struct vc_data *vc)
1564 {
1565 int i;
1566 int vc_num = vc->vc_num;
1567
1568 for (i = 0; i < 8; i++)
1569 speakup_console[vc_num]->ht.highsize[i] = 0;
1570 }
1571
1572 static int count_highlight_color(struct vc_data *vc)
1573 {
1574 int i, bg;
1575 int cc;
1576 int vc_num = vc->vc_num;
1577 u16 ch;
1578 u16 *start = (u16 *) vc->vc_origin;
1579
1580 for (i = 0; i < 8; i++)
1581 speakup_console[vc_num]->ht.bgcount[i] = 0;
1582
1583 for (i = 0; i < vc->vc_rows; i++) {
1584 u16 *end = start + vc->vc_cols * 2;
1585 u16 *ptr;
1586
1587 for (ptr = start; ptr < end; ptr++) {
1588 ch = get_attributes(ptr);
1589 bg = (ch & 0x70) >> 4;
1590 speakup_console[vc_num]->ht.bgcount[bg]++;
1591 }
1592 start += vc->vc_size_row;
1593 }
1594
1595 cc = 0;
1596 for (i = 0; i < 8; i++)
1597 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1598 cc++;
1599 return cc;
1600 }
1601
1602 static int get_highlight_color(struct vc_data *vc)
1603 {
1604 int i, j;
1605 unsigned int cptr[8];
1606 int vc_num = vc->vc_num;
1607
1608 for (i = 0; i < 8; i++)
1609 cptr[i] = i;
1610
1611 for (i = 0; i < 7; i++)
1612 for (j = i + 1; j < 8; j++)
1613 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1614 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1615 swap(cptr[i], cptr[j]);
1616
1617 for (i = 0; i < 8; i++)
1618 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1619 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1620 return cptr[i];
1621 return -1;
1622 }
1623
1624 static int speak_highlight(struct vc_data *vc)
1625 {
1626 int hc, d;
1627 int vc_num = vc->vc_num;
1628
1629 if (count_highlight_color(vc) == 1)
1630 return 0;
1631 hc = get_highlight_color(vc);
1632 if (hc != -1) {
1633 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1634 if ((d == 1) || (d == -1))
1635 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1636 return 0;
1637 spk_parked |= 0x01;
1638 spk_do_flush();
1639 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1640 speakup_console[vc_num]->ht.highsize[hc]);
1641 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1642 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1643 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1644 return 1;
1645 }
1646 return 0;
1647 }
1648
1649 static void cursor_done(u_long data)
1650 {
1651 struct vc_data *vc = vc_cons[cursor_con].d;
1652 unsigned long flags;
1653
1654 del_timer(&cursor_timer);
1655 spin_lock_irqsave(&speakup_info.spinlock, flags);
1656 if (cursor_con != fg_console) {
1657 is_cursor = 0;
1658 goto out;
1659 }
1660 speakup_date(vc);
1661 if (win_enabled) {
1662 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1663 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1664 spk_keydown = is_cursor = 0;
1665 goto out;
1666 }
1667 }
1668 if (cursor_track == read_all_mode) {
1669 handle_cursor_read_all(vc, read_all_key);
1670 goto out;
1671 }
1672 if (cursor_track == CT_Highlight) {
1673 if (speak_highlight(vc)) {
1674 spk_keydown = is_cursor = 0;
1675 goto out;
1676 }
1677 }
1678 if (cursor_track == CT_Window)
1679 speakup_win_say(vc);
1680 else if (is_cursor == 1 || is_cursor == 4)
1681 say_line_from_to(vc, 0, vc->vc_cols, 0);
1682 else
1683 say_char(vc);
1684 spk_keydown = is_cursor = 0;
1685 out:
1686 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1687 }
1688
1689 /* called by: vt_notifier_call() */
1690 static void speakup_bs(struct vc_data *vc)
1691 {
1692 unsigned long flags;
1693
1694 if (!speakup_console[vc->vc_num])
1695 return;
1696 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1697 /* Speakup output, discard */
1698 return;
1699 if (!spk_parked)
1700 speakup_date(vc);
1701 if (spk_shut_up || synth == NULL) {
1702 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1703 return;
1704 }
1705 if (vc->vc_num == fg_console && spk_keydown) {
1706 spk_keydown = 0;
1707 if (!is_cursor)
1708 say_char(vc);
1709 }
1710 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1711 }
1712
1713 /* called by: vt_notifier_call() */
1714 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1715 {
1716 unsigned long flags;
1717
1718 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1719 return;
1720 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1721 /* Speakup output, discard */
1722 return;
1723 if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1724 bleep(3);
1725 if ((is_cursor) || (cursor_track == read_all_mode)) {
1726 if (cursor_track == CT_Highlight)
1727 update_color_buffer(vc, str, len);
1728 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1729 return;
1730 }
1731 if (win_enabled) {
1732 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1733 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1734 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1735 return;
1736 }
1737 }
1738
1739 spkup_write(str, len);
1740 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1741 }
1742
1743 static void speakup_con_update(struct vc_data *vc)
1744 {
1745 unsigned long flags;
1746
1747 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1748 return;
1749 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1750 /* Speakup output, discard */
1751 return;
1752 speakup_date(vc);
1753 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1754 }
1755
1756 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1757 {
1758 unsigned long flags;
1759 int on_off = 2;
1760 char *label;
1761
1762 if (synth == NULL || up_flag || spk_killed)
1763 return;
1764 spin_lock_irqsave(&speakup_info.spinlock, flags);
1765 spk_shut_up &= 0xfe;
1766 if (spk_no_intr)
1767 spk_do_flush();
1768 switch (value) {
1769 case KVAL(K_CAPS):
1770 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1771 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1772 break;
1773 case KVAL(K_NUM):
1774 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1775 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1776 break;
1777 case KVAL(K_HOLD):
1778 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1779 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1780 if (speakup_console[vc->vc_num])
1781 speakup_console[vc->vc_num]->tty_stopped = on_off;
1782 break;
1783 default:
1784 spk_parked &= 0xfe;
1785 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1786 return;
1787 }
1788 if (on_off < 2)
1789 synth_printf("%s %s\n",
1790 label, spk_msg_get(MSG_STATUS_START + on_off));
1791 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1792 }
1793
1794 static int inc_dec_var(u_char value)
1795 {
1796 struct st_var_header *p_header;
1797 struct var_t *var_data;
1798 char num_buf[32];
1799 char *cp = num_buf;
1800 char *pn;
1801 int var_id = (int)value - VAR_START;
1802 int how = (var_id & 1) ? E_INC : E_DEC;
1803
1804 var_id = var_id / 2 + FIRST_SET_VAR;
1805 p_header = spk_get_var_header(var_id);
1806 if (p_header == NULL)
1807 return -1;
1808 if (p_header->var_type != VAR_NUM)
1809 return -1;
1810 var_data = p_header->data;
1811 if (spk_set_num_var(1, p_header, how) != 0)
1812 return -1;
1813 if (!spk_close_press) {
1814 for (pn = p_header->name; *pn; pn++) {
1815 if (*pn == '_')
1816 *cp = SPACE;
1817 else
1818 *cp++ = *pn;
1819 }
1820 }
1821 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1822 var_data->u.n.value);
1823 synth_printf("%s", num_buf);
1824 return 0;
1825 }
1826
1827 static void speakup_win_set(struct vc_data *vc)
1828 {
1829 char info[40];
1830
1831 if (win_start > 1) {
1832 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1833 return;
1834 }
1835 if (spk_x < win_left || spk_y < win_top) {
1836 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1837 return;
1838 }
1839 if (win_start && spk_x == win_left && spk_y == win_top) {
1840 win_left = 0;
1841 win_right = vc->vc_cols - 1;
1842 win_bottom = spk_y;
1843 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1844 (int)win_top + 1);
1845 } else {
1846 if (!win_start) {
1847 win_top = spk_y;
1848 win_left = spk_x;
1849 } else {
1850 win_bottom = spk_y;
1851 win_right = spk_x;
1852 }
1853 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1854 (win_start) ?
1855 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1856 (int)spk_y + 1, (int)spk_x + 1);
1857 }
1858 synth_printf("%s\n", info);
1859 win_start++;
1860 }
1861
1862 static void speakup_win_clear(struct vc_data *vc)
1863 {
1864 win_top = win_bottom = 0;
1865 win_left = win_right = 0;
1866 win_start = 0;
1867 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1868 }
1869
1870 static void speakup_win_enable(struct vc_data *vc)
1871 {
1872 if (win_start < 2) {
1873 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1874 return;
1875 }
1876 win_enabled ^= 1;
1877 if (win_enabled)
1878 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1879 else
1880 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1881 }
1882
1883 static void speakup_bits(struct vc_data *vc)
1884 {
1885 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1886
1887 if (spk_special_handler != NULL || val < 1 || val > 6) {
1888 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1889 return;
1890 }
1891 pb_edit = &spk_punc_info[val];
1892 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1893 spk_special_handler = edit_bits;
1894 }
1895
1896 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1897 {
1898 static u_char goto_buf[8];
1899 static int num;
1900 int maxlen;
1901 char *cp;
1902
1903 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1904 goto do_goto;
1905 if (type == KT_LATIN && ch == '\n')
1906 goto do_goto;
1907 if (type != 0)
1908 goto oops;
1909 if (ch == 8) {
1910 if (num == 0)
1911 return -1;
1912 ch = goto_buf[--num];
1913 goto_buf[num] = '\0';
1914 spkup_write(&ch, 1);
1915 return 1;
1916 }
1917 if (ch < '+' || ch > 'y')
1918 goto oops;
1919 goto_buf[num++] = ch;
1920 goto_buf[num] = '\0';
1921 spkup_write(&ch, 1);
1922 maxlen = (*goto_buf >= '0') ? 3 : 4;
1923 if ((ch == '+' || ch == '-') && num == 1)
1924 return 1;
1925 if (ch >= '0' && ch <= '9' && num < maxlen)
1926 return 1;
1927 if (num < maxlen - 1 || num > maxlen)
1928 goto oops;
1929 if (ch < 'x' || ch > 'y') {
1930 oops:
1931 if (!spk_killed)
1932 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1933 goto_buf[num = 0] = '\0';
1934 spk_special_handler = NULL;
1935 return 1;
1936 }
1937
1938 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1939
1940 if (*cp == 'x') {
1941 if (*goto_buf < '0')
1942 goto_pos += spk_x;
1943 else if (goto_pos > 0)
1944 goto_pos--;
1945
1946 if (goto_pos >= vc->vc_cols)
1947 goto_pos = vc->vc_cols - 1;
1948 goto_x = 1;
1949 } else {
1950 if (*goto_buf < '0')
1951 goto_pos += spk_y;
1952 else if (goto_pos > 0)
1953 goto_pos--;
1954
1955 if (goto_pos >= vc->vc_rows)
1956 goto_pos = vc->vc_rows - 1;
1957 goto_x = 0;
1958 }
1959 goto_buf[num = 0] = '\0';
1960 do_goto:
1961 spk_special_handler = NULL;
1962 spk_parked |= 0x01;
1963 if (goto_x) {
1964 spk_pos -= spk_x * 2;
1965 spk_x = goto_pos;
1966 spk_pos += goto_pos * 2;
1967 say_word(vc);
1968 } else {
1969 spk_y = goto_pos;
1970 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1971 say_line(vc);
1972 }
1973 return 1;
1974 }
1975
1976 static void speakup_goto(struct vc_data *vc)
1977 {
1978 if (spk_special_handler != NULL) {
1979 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1980 return;
1981 }
1982 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1983 spk_special_handler = handle_goto;
1984 }
1985
1986 static void speakup_help(struct vc_data *vc)
1987 {
1988 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1989 }
1990
1991 static void do_nothing(struct vc_data *vc)
1992 {
1993 return; /* flush done in do_spkup */
1994 }
1995
1996 static u_char key_speakup, spk_key_locked;
1997
1998 static void speakup_lock(struct vc_data *vc)
1999 {
2000 if (!spk_key_locked)
2001 spk_key_locked = key_speakup = 16;
2002 else
2003 spk_key_locked = key_speakup = 0;
2004 }
2005
2006 typedef void (*spkup_hand) (struct vc_data *);
2007 static spkup_hand spkup_handler[] = {
2008 /* must be ordered same as defines in speakup.h */
2009 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2010 speakup_cut, speakup_paste, say_first_char, say_last_char,
2011 say_char, say_prev_char, say_next_char,
2012 say_word, say_prev_word, say_next_word,
2013 say_line, say_prev_line, say_next_line,
2014 top_edge, bottom_edge, left_edge, right_edge,
2015 spell_word, spell_word, say_screen,
2016 say_position, say_attributes,
2017 speakup_off, speakup_parked, say_line, /* this is for indent */
2018 say_from_top, say_to_bottom,
2019 say_from_left, say_to_right,
2020 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2021 speakup_bits, speakup_bits, speakup_bits,
2022 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2023 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2024 };
2025
2026 static void do_spkup(struct vc_data *vc, u_char value)
2027 {
2028 if (spk_killed && value != SPEECH_KILL)
2029 return;
2030 spk_keydown = 0;
2031 spk_lastkey = 0;
2032 spk_shut_up &= 0xfe;
2033 this_speakup_key = value;
2034 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2035 spk_do_flush();
2036 (*spkup_handler[value]) (vc);
2037 } else {
2038 if (inc_dec_var(value) < 0)
2039 bleep(9);
2040 }
2041 }
2042
2043 static const char *pad_chars = "0123456789+-*/\015,.?()";
2044
2045 static int
2046 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2047 int up_flag)
2048 {
2049 unsigned long flags;
2050 int kh;
2051 u_char *key_info;
2052 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2053 u_char shift_info, offset;
2054 int ret = 0;
2055
2056 if (synth == NULL)
2057 return 0;
2058
2059 spin_lock_irqsave(&speakup_info.spinlock, flags);
2060 tty = vc->port.tty;
2061 if (type >= 0xf0)
2062 type -= 0xf0;
2063 if (type == KT_PAD
2064 && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2065 if (up_flag) {
2066 spk_keydown = 0;
2067 goto out;
2068 }
2069 value = spk_lastkey = pad_chars[value];
2070 spk_keydown++;
2071 spk_parked &= 0xfe;
2072 goto no_map;
2073 }
2074 if (keycode >= MAX_KEY)
2075 goto no_map;
2076 key_info = spk_our_keys[keycode];
2077 if (!key_info)
2078 goto no_map;
2079 /* Check valid read all mode keys */
2080 if ((cursor_track == read_all_mode) && (!up_flag)) {
2081 switch (value) {
2082 case KVAL(K_DOWN):
2083 case KVAL(K_UP):
2084 case KVAL(K_LEFT):
2085 case KVAL(K_RIGHT):
2086 case KVAL(K_PGUP):
2087 case KVAL(K_PGDN):
2088 break;
2089 default:
2090 stop_read_all(vc);
2091 break;
2092 }
2093 }
2094 shift_info = (shift_state & 0x0f) + key_speakup;
2095 offset = spk_shift_table[shift_info];
2096 if (offset) {
2097 new_key = key_info[offset];
2098 if (new_key) {
2099 ret = 1;
2100 if (new_key == SPK_KEY) {
2101 if (!spk_key_locked)
2102 key_speakup = (up_flag) ? 0 : 16;
2103 if (up_flag || spk_killed)
2104 goto out;
2105 spk_shut_up &= 0xfe;
2106 spk_do_flush();
2107 goto out;
2108 }
2109 if (up_flag)
2110 goto out;
2111 if (last_keycode == keycode &&
2112 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2113 spk_close_press = 1;
2114 offset = spk_shift_table[shift_info + 32];
2115 /* double press? */
2116 if (offset && key_info[offset])
2117 new_key = key_info[offset];
2118 }
2119 last_keycode = keycode;
2120 last_spk_jiffy = jiffies;
2121 type = KT_SPKUP;
2122 value = new_key;
2123 }
2124 }
2125 no_map:
2126 if (type == KT_SPKUP && spk_special_handler == NULL) {
2127 do_spkup(vc, new_key);
2128 spk_close_press = 0;
2129 ret = 1;
2130 goto out;
2131 }
2132 if (up_flag || spk_killed || type == KT_SHIFT)
2133 goto out;
2134 spk_shut_up &= 0xfe;
2135 kh = (value == KVAL(K_DOWN))
2136 || (value == KVAL(K_UP))
2137 || (value == KVAL(K_LEFT))
2138 || (value == KVAL(K_RIGHT));
2139 if ((cursor_track != read_all_mode) || !kh)
2140 if (!spk_no_intr)
2141 spk_do_flush();
2142 if (spk_special_handler) {
2143 if (type == KT_SPEC && value == 1) {
2144 value = '\n';
2145 type = KT_LATIN;
2146 } else if (type == KT_LETTER)
2147 type = KT_LATIN;
2148 else if (value == 0x7f)
2149 value = 8; /* make del = backspace */
2150 ret = (*spk_special_handler) (vc, type, value, keycode);
2151 spk_close_press = 0;
2152 if (ret < 0)
2153 bleep(9);
2154 goto out;
2155 }
2156 last_keycode = 0;
2157 out:
2158 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2159 return ret;
2160 }
2161
2162 static int keyboard_notifier_call(struct notifier_block *nb,
2163 unsigned long code, void *_param)
2164 {
2165 struct keyboard_notifier_param *param = _param;
2166 struct vc_data *vc = param->vc;
2167 int up = !param->down;
2168 int ret = NOTIFY_OK;
2169 static int keycode; /* to hold the current keycode */
2170
2171 if (vc->vc_mode == KD_GRAPHICS)
2172 return ret;
2173
2174 /*
2175 * First, determine whether we are handling a fake keypress on
2176 * the current processor. If we are, then return NOTIFY_OK,
2177 * to pass the keystroke up the chain. This prevents us from
2178 * trying to take the Speakup lock while it is held by the
2179 * processor on which the simulated keystroke was generated.
2180 * Also, the simulated keystrokes should be ignored by Speakup.
2181 */
2182
2183 if (speakup_fake_key_pressed())
2184 return ret;
2185
2186 switch (code) {
2187 case KBD_KEYCODE:
2188 /* speakup requires keycode and keysym currently */
2189 keycode = param->value;
2190 break;
2191 case KBD_UNBOUND_KEYCODE:
2192 /* not used yet */
2193 break;
2194 case KBD_UNICODE:
2195 /* not used yet */
2196 break;
2197 case KBD_KEYSYM:
2198 if (speakup_key(vc, param->shift, keycode, param->value, up))
2199 ret = NOTIFY_STOP;
2200 else if (KTYP(param->value) == KT_CUR)
2201 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2202 break;
2203 case KBD_POST_KEYSYM:{
2204 unsigned char type = KTYP(param->value) - 0xf0;
2205 unsigned char val = KVAL(param->value);
2206
2207 switch (type) {
2208 case KT_SHIFT:
2209 do_handle_shift(vc, val, up);
2210 break;
2211 case KT_LATIN:
2212 case KT_LETTER:
2213 do_handle_latin(vc, val, up);
2214 break;
2215 case KT_CUR:
2216 do_handle_cursor(vc, val, up);
2217 break;
2218 case KT_SPEC:
2219 do_handle_spec(vc, val, up);
2220 break;
2221 }
2222 break;
2223 }
2224 }
2225 return ret;
2226 }
2227
2228 static int vt_notifier_call(struct notifier_block *nb,
2229 unsigned long code, void *_param)
2230 {
2231 struct vt_notifier_param *param = _param;
2232 struct vc_data *vc = param->vc;
2233
2234 switch (code) {
2235 case VT_ALLOCATE:
2236 if (vc->vc_mode == KD_TEXT)
2237 speakup_allocate(vc);
2238 break;
2239 case VT_DEALLOCATE:
2240 speakup_deallocate(vc);
2241 break;
2242 case VT_WRITE:
2243 if (param->c == '\b')
2244 speakup_bs(vc);
2245 else if (param->c < 0x100) {
2246 char d = param->c;
2247
2248 speakup_con_write(vc, &d, 1);
2249 }
2250 break;
2251 case VT_UPDATE:
2252 speakup_con_update(vc);
2253 break;
2254 }
2255 return NOTIFY_OK;
2256 }
2257
2258 /* called by: module_exit() */
2259 static void __exit speakup_exit(void)
2260 {
2261 int i;
2262
2263 unregister_keyboard_notifier(&keyboard_notifier_block);
2264 unregister_vt_notifier(&vt_notifier_block);
2265 speakup_unregister_devsynth();
2266 speakup_cancel_paste();
2267 del_timer(&cursor_timer);
2268 kthread_stop(speakup_task);
2269 speakup_task = NULL;
2270 mutex_lock(&spk_mutex);
2271 synth_release();
2272 mutex_unlock(&spk_mutex);
2273
2274 speakup_kobj_exit();
2275
2276 for (i = 0; i < MAX_NR_CONSOLES; i++)
2277 kfree(speakup_console[i]);
2278
2279 speakup_remove_virtual_keyboard();
2280
2281 for (i = 0; i < MAXVARS; i++)
2282 speakup_unregister_var(i);
2283
2284 for (i = 0; i < 256; i++) {
2285 if (spk_characters[i] != spk_default_chars[i])
2286 kfree(spk_characters[i]);
2287 }
2288
2289 spk_free_user_msgs();
2290 }
2291
2292 /* call by: module_init() */
2293 static int __init speakup_init(void)
2294 {
2295 int i;
2296 long err = 0;
2297 struct st_spk_t *first_console;
2298 struct vc_data *vc = vc_cons[fg_console].d;
2299 struct var_t *var;
2300
2301 /* These first few initializations cannot fail. */
2302 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2303 spk_reset_default_chars();
2304 spk_reset_default_chartab();
2305 spk_strlwr(synth_name);
2306 spk_vars[0].u.n.high = vc->vc_cols;
2307 for (var = spk_vars; var->var_id != MAXVARS; var++)
2308 speakup_register_var(var);
2309 for (var = synth_time_vars;
2310 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2311 speakup_register_var(var);
2312 for (i = 1; spk_punc_info[i].mask != 0; i++)
2313 spk_set_mask_bits(NULL, i, 2);
2314
2315 spk_set_key_info(spk_key_defaults, spk_key_buf);
2316
2317 /* From here on out, initializations can fail. */
2318 err = speakup_add_virtual_keyboard();
2319 if (err)
2320 goto error_virtkeyboard;
2321
2322 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2323 if (!first_console) {
2324 err = -ENOMEM;
2325 goto error_alloc;
2326 }
2327
2328 speakup_console[vc->vc_num] = first_console;
2329 speakup_date(vc);
2330
2331 for (i = 0; i < MAX_NR_CONSOLES; i++)
2332 if (vc_cons[i].d) {
2333 err = speakup_allocate(vc_cons[i].d);
2334 if (err)
2335 goto error_kobjects;
2336 }
2337
2338 if (spk_quiet_boot)
2339 spk_shut_up |= 0x01;
2340
2341 err = speakup_kobj_init();
2342 if (err)
2343 goto error_kobjects;
2344
2345 synth_init(synth_name);
2346 speakup_register_devsynth();
2347 /*
2348 * register_devsynth might fail, but this error is not fatal.
2349 * /dev/synth is an extra feature; the rest of Speakup
2350 * will work fine without it.
2351 */
2352
2353 err = register_keyboard_notifier(&keyboard_notifier_block);
2354 if (err)
2355 goto error_kbdnotifier;
2356 err = register_vt_notifier(&vt_notifier_block);
2357 if (err)
2358 goto error_vtnotifier;
2359
2360 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2361
2362 if (IS_ERR(speakup_task)) {
2363 err = PTR_ERR(speakup_task);
2364 goto error_task;
2365 }
2366
2367 set_user_nice(speakup_task, 10);
2368 wake_up_process(speakup_task);
2369
2370 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2371 pr_info("synth name on entry is: %s\n", synth_name);
2372 goto out;
2373
2374 error_task:
2375 unregister_vt_notifier(&vt_notifier_block);
2376
2377 error_vtnotifier:
2378 unregister_keyboard_notifier(&keyboard_notifier_block);
2379 del_timer(&cursor_timer);
2380
2381 error_kbdnotifier:
2382 speakup_unregister_devsynth();
2383 mutex_lock(&spk_mutex);
2384 synth_release();
2385 mutex_unlock(&spk_mutex);
2386 speakup_kobj_exit();
2387
2388 error_kobjects:
2389 for (i = 0; i < MAX_NR_CONSOLES; i++)
2390 kfree(speakup_console[i]);
2391
2392 error_alloc:
2393 speakup_remove_virtual_keyboard();
2394
2395 error_virtkeyboard:
2396 for (i = 0; i < MAXVARS; i++)
2397 speakup_unregister_var(i);
2398
2399 for (i = 0; i < 256; i++) {
2400 if (spk_characters[i] != spk_default_chars[i])
2401 kfree(spk_characters[i]);
2402 }
2403
2404 spk_free_user_msgs();
2405
2406 out:
2407 return err;
2408 }
2409
2410 module_init(speakup_init);
2411 module_exit(speakup_exit);
This page took 0.079526 seconds and 6 git commands to generate.