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