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