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