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