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