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