ocfs2: Make the left masklogs compat.
[taoma-kernel.git] / drivers / staging / speakup / main.c
blob3cd00396a462baf3d3837ca192778c25f746c683
1 /* speakup.c
2 * review functions for the speakup screen review package.
3 * originally written by: Kirk Reiser and Andy Berdan.
5 * extensively modified by David Borowski.
7 ** Copyright (C) 1998 Kirk Reiser.
8 * Copyright (C) 2003 David Borowski.
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.
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.
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
25 #include <linux/kernel.h>
26 #include <linux/version.h>
27 #include <linux/vt.h>
28 #include <linux/tty.h>
29 #include <linux/mm.h> /* __get_free_page() and friends */
30 #include <linux/vt_kern.h>
31 #include <linux/ctype.h>
32 #include <linux/selection.h>
33 #include <linux/unistd.h>
34 #include <linux/jiffies.h>
35 #include <linux/kthread.h>
36 #include <linux/keyboard.h> /* for KT_SHIFT */
37 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
38 #include <linux/input.h>
39 #include <linux/kmod.h>
41 #include <linux/bootmem.h> /* for alloc_bootmem */
43 /* speakup_*_selection */
44 #include <linux/module.h>
45 #include <linux/sched.h>
46 #include <linux/slab.h>
47 #include <linux/types.h>
48 #include <linux/consolemap.h>
50 #include <linux/spinlock.h>
51 #include <linux/notifier.h>
53 #include <linux/uaccess.h> /* copy_from|to|user() and others */
55 #include "spk_priv.h"
56 #include "speakup.h"
58 #define MAX_DELAY msecs_to_jiffies(500)
59 #define MINECHOCHAR SPACE
61 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
62 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
63 MODULE_DESCRIPTION("Speakup console speech");
64 MODULE_LICENSE("GPL");
65 MODULE_VERSION(SPEAKUP_VERSION);
67 char *synth_name;
68 module_param_named(synth, synth_name, charp, S_IRUGO);
69 module_param_named(quiet, quiet_boot, bool, S_IRUGO);
71 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
72 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
74 special_func special_handler;
76 short pitch_shift, synth_flags;
77 static char buf[256];
78 int attrib_bleep, bleeps, bleep_time = 10;
79 int no_intr, spell_delay;
80 int key_echo, say_word_ctl;
81 int say_ctrl, bell_pos;
82 short punc_mask;
83 int punc_level, reading_punc;
84 char str_caps_start[MAXVARLEN + 1] = "\0", str_caps_stop[MAXVARLEN + 1] = "\0";
85 const struct st_bits_data punc_info[] = {
86 {"none", "", 0},
87 {"some", "/$%&@", SOME},
88 {"most", "$%&#()=+*/@^<>|\\", MOST},
89 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
90 {"delimiters", "", B_WDLM},
91 {"repeats", "()", CH_RPT},
92 {"extended numeric", "", B_EXNUM},
93 {"symbols", "", B_SYM},
94 {0, 0}
97 static char mark_cut_flag;
98 #define MAX_KEY 160
99 u_char *our_keys[MAX_KEY], *shift_table;
100 u_char key_buf[600];
101 const u_char key_defaults[] = {
102 #include "speakupmap.h"
105 /* Speakup Cursor Track Variables */
106 static int cursor_track = 1, prev_cursor_track = 1;
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
116 #define read_all_mode CT_Max
118 static struct tty_struct *tty;
120 static void spkup_write(const char *in_buf, int count);
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"
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 *characters[256];
135 char *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"
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];
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 */
241 struct task_struct *speakup_task;
242 struct bleep 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;
248 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
250 DEFINE_MUTEX(spk_mutex);
252 static int keyboard_notifier_call(struct notifier_block *,
253 unsigned long code, void *param);
255 struct notifier_block keyboard_notifier_block = {
256 .notifier_call = keyboard_notifier_call,
259 static int vt_notifier_call(struct notifier_block *,
260 unsigned long code, void *param);
262 struct notifier_block vt_notifier_block = {
263 .notifier_call = vt_notifier_call,
266 static unsigned char get_attributes(u16 *pos)
268 return (u_char) (scr_readw(pos) >> 8);
271 static void speakup_date(struct vc_data *vc)
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);
280 static void bleep(u_short val)
282 static const short vals[] = {
283 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
285 short freq;
286 int time = bleep_time;
287 freq = vals[val % 12];
288 if (val > 11)
289 freq *= (1 << (val / 12));
290 unprocessed_sound.freq = freq;
291 unprocessed_sound.jiffies = msecs_to_jiffies(time);
292 unprocessed_sound.active = 1;
293 /* We can only have 1 active sound at a time. */
296 static void speakup_shut_up(struct vc_data *vc)
298 if (spk_killed)
299 return;
300 spk_shut_up |= 0x01;
301 spk_parked &= 0xfe;
302 speakup_date(vc);
303 if (synth != NULL)
304 do_flush();
307 static void speech_kill(struct vc_data *vc)
309 char val = synth->is_alive(synth);
310 if (val == 0)
311 return;
313 /* re-enables synth, if disabled */
314 if (val == 2 || spk_killed) {
315 /* dead */
316 spk_shut_up &= ~0x40;
317 synth_printf("%s\n", msg_get(MSG_IAM_ALIVE));
318 } else {
319 synth_printf("%s\n", msg_get(MSG_YOU_KILLED_SPEAKUP));
320 spk_shut_up |= 0x40;
324 static void speakup_off(struct vc_data *vc)
326 if (spk_shut_up & 0x80) {
327 spk_shut_up &= 0x7f;
328 synth_printf("%s\n", msg_get(MSG_HEY_THATS_BETTER));
329 } else {
330 spk_shut_up |= 0x80;
331 synth_printf("%s\n", msg_get(MSG_YOU_TURNED_ME_OFF));
333 speakup_date(vc);
336 static void speakup_parked(struct vc_data *vc)
338 if (spk_parked & 0x80) {
339 spk_parked = 0;
340 synth_printf("%s\n", msg_get(MSG_UNPARKED));
341 } else {
342 spk_parked |= 0x80;
343 synth_printf("%s\n", msg_get(MSG_PARKED));
347 static void speakup_cut(struct vc_data *vc)
349 static const char err_buf[] = "set selection failed";
350 int ret;
352 if (!mark_cut_flag) {
353 mark_cut_flag = 1;
354 xs = (u_short) spk_x;
355 ys = (u_short) spk_y;
356 spk_sel_cons = vc;
357 synth_printf("%s\n", msg_get(MSG_MARK));
358 return;
360 xe = (u_short) spk_x;
361 ye = (u_short) spk_y;
362 mark_cut_flag = 0;
363 synth_printf("%s\n", msg_get(MSG_CUT));
365 speakup_clear_selection();
366 ret = speakup_set_selection(tty);
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;
383 static void speakup_paste(struct vc_data *vc)
385 if (mark_cut_flag) {
386 mark_cut_flag = 0;
387 synth_printf("%s\n", msg_get(MSG_MARK_CLEARED));
388 } else {
389 synth_printf("%s\n", msg_get(MSG_PASTE));
390 speakup_paste_selection(tty);
394 static void say_attributes(struct vc_data *vc)
396 int fg = spk_attr & 0x0f;
397 int bg = spk_attr >> 4;
398 if (fg > 8) {
399 synth_printf("%s ", msg_get(MSG_BRIGHT));
400 fg -= 8;
402 synth_printf("%s", msg_get(MSG_COLORS_START + fg));
403 if (bg > 7) {
404 synth_printf(" %s ", msg_get(MSG_ON_BLINKING));
405 bg -= 8;
406 } else
407 synth_printf(" %s ", msg_get(MSG_ON));
408 synth_printf("%s\n", msg_get(MSG_COLORS_START + bg));
411 enum {
412 edge_top = 1,
413 edge_bottom,
414 edge_left,
415 edge_right,
416 edge_quiet
419 static void announce_edge(struct vc_data *vc, int msg_id)
421 if (bleeps & 1)
422 bleep(spk_y);
423 if ((bleeps & 2) && (msg_id < edge_quiet))
424 synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
427 static void speak_char(u_char ch)
429 char *cp = characters[ch];
430 struct var_t *direct = get_var(DIRECT);
431 if (direct && direct->u.n.value) {
432 if (IS_CHAR(ch, B_CAP)) {
433 pitch_shift++;
434 synth_printf("%s", str_caps_start);
436 synth_printf("%c", ch);
437 if (IS_CHAR(ch, B_CAP))
438 synth_printf("%s", str_caps_stop);
439 return;
441 if (cp == NULL) {
442 pr_info("speak_char: cp == NULL!\n");
443 return;
445 synth_buffer_add(SPACE);
446 if (IS_CHAR(ch, B_CAP)) {
447 pitch_shift++;
448 synth_printf("%s", str_caps_start);
449 synth_printf("%s", cp);
450 synth_printf("%s", str_caps_stop);
451 } else {
452 if (*cp == '^') {
453 synth_printf("%s", msg_get(MSG_CTRL));
454 cp++;
456 synth_printf("%s", cp);
458 synth_buffer_add(SPACE);
461 static u16 get_char(struct vc_data *vc, u16 * pos, u_char * attribs)
463 u16 ch = ' ';
464 if (vc && pos) {
465 u16 w = scr_readw(pos);
466 u16 c = w & 0xff;
468 if (w & vc->vc_hi_font_mask)
469 c |= 0x100;
471 ch = inverse_translate(vc, c, 0);
472 *attribs = (w & 0xff00) >> 8;
474 return ch;
477 static void say_char(struct vc_data *vc)
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 (attrib_bleep & 1)
484 bleep(spk_y);
485 if (attrib_bleep & 2)
486 say_attributes(vc);
488 speak_char(ch & 0xff);
491 static void say_phonetic_char(struct vc_data *vc)
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 ", msg_get(MSG_NUMBER));
502 speak_char(ch);
506 static void say_prev_char(struct vc_data *vc)
508 spk_parked |= 0x01;
509 if (spk_x == 0) {
510 announce_edge(vc, edge_left);
511 return;
513 spk_x--;
514 spk_pos -= 2;
515 say_char(vc);
518 static void say_next_char(struct vc_data *vc)
520 spk_parked |= 0x01;
521 if (spk_x == vc->vc_cols - 1) {
522 announce_edge(vc, edge_right);
523 return;
525 spk_x++;
526 spk_pos += 2;
527 say_char(vc);
530 /* get_word - will first check to see if the character under the
531 * reading cursor is a space and if say_word_ctl is true it will
532 * return the word space. If 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.. */
538 static u_long get_word(struct vc_data *vc)
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);
547 /* decided to take out the sayword if on a space (mis-information */
548 if (say_word_ctl && ch == SPACE) {
549 *buf = '\0';
550 synth_printf("%s\n", 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--;
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;
579 buf[cnt] = '\0';
580 return cnt;
583 static void say_word(struct vc_data *vc)
585 u_long cnt = get_word(vc);
586 u_short saved_punc_mask = punc_mask;
587 if (cnt == 0)
588 return;
589 punc_mask = PUNC;
590 buf[cnt++] = SPACE;
591 spkup_write(buf, cnt);
592 punc_mask = saved_punc_mask;
595 static void say_prev_word(struct vc_data *vc)
597 u_char temp;
598 char ch;
599 u_short edge_said = 0, last_state = 0, state = 0;
600 spk_parked |= 0x01;
602 if (spk_x == 0) {
603 if (spk_y == 0) {
604 announce_edge(vc, edge_top);
605 return;
607 spk_y--;
608 spk_x = vc->vc_cols;
609 edge_said = edge_quiet;
611 while (1) {
612 if (spk_x == 0) {
613 if (spk_y == 0) {
614 edge_said = edge_top;
615 break;
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;
638 last_state = state;
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);
647 static void say_next_word(struct vc_data *vc)
649 u_char temp;
650 char ch;
651 u_short edge_said = 0, last_state = 2, state = 0;
652 spk_parked |= 0x01;
654 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
655 announce_edge(vc, edge_bottom);
656 return;
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;
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;
682 if (edge_said > 0)
683 announce_edge(vc, edge_said);
684 say_word(vc);
687 static void spell_word(struct vc_data *vc)
689 static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
690 char *cp = buf, *str_cap = str_caps_stop;
691 char *cp1, *last_cap = 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[spell_delay]);
698 if (IS_CHAR(ch, B_CAP)) {
699 str_cap = str_caps_start;
700 if (*str_caps_stop)
701 pitch_shift++;
702 else /* synth has no pitch */
703 last_cap = str_caps_stop;
704 } else
705 str_cap = str_caps_stop;
706 if (str_cap != last_cap) {
707 synth_printf("%s", str_cap);
708 last_cap = str_cap;
710 if (this_speakup_key == SPELL_PHONETIC
711 && (isascii(ch) && isalpha(ch))) {
712 ch &= 31;
713 cp1 = phonetic[--ch];
714 } else {
715 cp1 = characters[ch];
716 if (*cp1 == '^') {
717 synth_printf("%s", msg_get(MSG_CTRL));
718 cp1++;
721 synth_printf("%s", cp1);
722 cp++;
724 if (str_cap != str_caps_stop)
725 synth_printf("%s", str_caps_stop);
728 static int get_line(struct vc_data *vc)
730 u_long tmp = spk_pos - (spk_x * 2);
731 int i = 0;
732 u_char tmp2;
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;
740 for (--i; i >= 0; i--)
741 if (buf[i] != SPACE)
742 break;
743 return ++i;
746 static void say_line(struct vc_data *vc)
748 int i = get_line(vc);
749 char *cp;
750 u_short saved_punc_mask = punc_mask;
751 if (i == 0) {
752 synth_printf("%s\n", msg_get(MSG_BLANK));
753 return;
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);
762 punc_mask = punc_masks[reading_punc];
763 spkup_write(buf, i);
764 punc_mask = saved_punc_mask;
767 static void say_prev_line(struct vc_data *vc)
769 spk_parked |= 0x01;
770 if (spk_y == 0) {
771 announce_edge(vc, edge_top);
772 return;
774 spk_y--;
775 spk_pos -= vc->vc_size_row;
776 say_line(vc);
779 static void say_next_line(struct vc_data *vc)
781 spk_parked |= 0x01;
782 if (spk_y == vc->vc_rows - 1) {
783 announce_edge(vc, edge_bottom);
784 return;
786 spk_y++;
787 spk_pos += vc->vc_size_row;
788 say_line(vc);
791 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
792 int read_punc)
794 int i = 0;
795 u_char tmp;
796 u_short saved_punc_mask = 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;
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 punc_mask = punc_info[reading_punc].mask;
814 spkup_write(buf, i);
815 if (read_punc)
816 punc_mask = saved_punc_mask;
817 return i - 1;
820 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
821 int read_punc)
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", msg_get(MSG_BLANK));
831 /* Sentence Reading Commands */
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];
841 static int say_sentence_num(int num, int prev)
843 bn = currbuf;
844 currsentence = num + 1;
845 if (prev && --bn == -1)
846 bn = 1;
848 if (num > numsentences[bn])
849 return 0;
851 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
852 return 1;
855 static int get_sentence_buf(struct vc_data *vc, int read_punc)
857 u_long start, end;
858 int i, bn;
859 u_char tmp;
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;
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);
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];
885 i++;
886 start += 2;
887 if (i >= vc->vc_size_row)
888 break;
891 for (--i; i >= 0; i--)
892 if (sentbuf[bn][i] != SPACE)
893 break;
895 if (i < 1)
896 return -1;
898 sentbuf[bn][++i] = SPACE;
899 sentbuf[bn][++i] = '\0';
901 sentbufend[bn] = &sentbuf[bn][i];
902 return numsentences[bn];
905 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
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);
919 static void say_screen(struct vc_data *vc)
921 say_screen_from_to(vc, 0, vc->vc_rows);
924 static void speakup_win_say(struct vc_data *vc)
926 u_long start, end, from, to;
927 if (win_start < 2) {
928 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
929 return;
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;
941 static void top_edge(struct vc_data *vc)
943 spk_parked |= 0x01;
944 spk_pos = vc->vc_origin + 2 * spk_x;
945 spk_y = 0;
946 say_line(vc);
949 static void bottom_edge(struct vc_data *vc)
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);
957 static void left_edge(struct vc_data *vc)
959 spk_parked |= 0x01;
960 spk_pos -= spk_x * 2;
961 spk_x = 0;
962 say_char(vc);
965 static void right_edge(struct vc_data *vc)
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);
973 static void say_first_char(struct vc_data *vc)
975 int i, len = get_line(vc);
976 u_char ch;
977 spk_parked |= 0x01;
978 if (len == 0) {
979 synth_printf("%s\n", msg_get(MSG_BLANK));
980 return;
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);
992 static void say_last_char(struct vc_data *vc)
994 int len = get_line(vc);
995 u_char ch;
996 spk_parked |= 0x01;
997 if (len == 0) {
998 synth_printf("%s\n", msg_get(MSG_BLANK));
999 return;
1001 ch = buf[--len];
1002 spk_pos -= (spk_x - len) * 2;
1003 spk_x = len;
1004 synth_printf("%d, ", ++len);
1005 speak_char(ch);
1008 static void say_position(struct vc_data *vc)
1010 synth_printf(msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1011 vc->vc_num + 1);
1012 synth_printf("\n");
1015 /* Added by brianb */
1016 static void say_char_num(struct vc_data *vc)
1018 u_char tmp;
1019 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1020 ch &= 0xff;
1021 synth_printf(msg_get(MSG_CHAR_INFO), ch, ch);
1024 /* these are stub functions to keep keyboard.c happy. */
1026 static void say_from_top(struct vc_data *vc)
1028 say_screen_from_to(vc, 0, spk_y);
1031 static void say_to_bottom(struct vc_data *vc)
1033 say_screen_from_to(vc, spk_y, vc->vc_rows);
1036 static void say_from_left(struct vc_data *vc)
1038 say_line_from_to(vc, 0, spk_x, 1);
1041 static void say_to_right(struct vc_data *vc)
1043 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1046 /* end of stub functions. */
1048 static void spkup_write(const char *in_buf, int count)
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++);
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(msg_get(MSG_REPEAT_DESC),
1071 ++rep_count);
1072 synth_printf(" ");
1074 rep_count = 0;
1076 if (ch == spk_lastkey) {
1077 rep_count = 0;
1078 if (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 & 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;
1108 old_ch = ch;
1109 last_type = char_type;
1111 spk_lastkey = 0;
1112 if (in_count > 2 && rep_count > 2) {
1113 if (last_type & CH_RPT) {
1114 synth_printf(" ");
1115 synth_printf(msg_get(MSG_REPEAT_DESC2), ++rep_count);
1116 synth_printf(" ");
1118 rep_count = 0;
1122 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
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);
1128 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1130 unsigned long flags;
1131 if (synth == NULL || up_flag || spk_killed)
1132 return;
1133 spk_lock(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 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 do_flush();
1147 break;
1149 } else {
1150 spk_shut_up &= 0xfe;
1151 do_flush();
1153 if (say_ctrl && value < NUM_CTL_LABELS)
1154 synth_printf("%s", msg_get(MSG_CTL_START + value));
1155 spk_unlock(flags);
1158 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1160 unsigned long flags;
1161 spk_lock(flags);
1162 if (up_flag) {
1163 spk_lastkey = spk_keydown = 0;
1164 spk_unlock(flags);
1165 return;
1167 if (synth == NULL || spk_killed) {
1168 spk_unlock(flags);
1169 return;
1171 spk_shut_up &= 0xfe;
1172 spk_lastkey = value;
1173 spk_keydown++;
1174 spk_parked &= 0xfe;
1175 if (key_echo == 2 && value >= MINECHOCHAR)
1176 speak_char(value);
1177 spk_unlock(flags);
1180 int set_key_info(const u_char *key_info, u_char *k_buffer)
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(key_buf))
1193 return -2;
1194 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1195 memset(our_keys, 0, sizeof(our_keys));
1196 shift_table = k_buffer;
1197 our_keys[0] = 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 shift_table[ch] = i;
1208 keymap_flags = *cp1++;
1209 while ((ch = *cp1)) {
1210 if (ch >= MAX_KEY)
1211 return -4;
1212 our_keys[ch] = cp1;
1213 cp1 += states + 1;
1215 return 0;
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
1235 static void toggle_cursoring(struct vc_data *vc)
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", msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1244 void reset_default_chars(void)
1246 int i;
1248 /* First, free any non-default */
1249 for (i = 0; i < 256; i++) {
1250 if ((characters[i] != NULL)
1251 && (characters[i] != default_chars[i]))
1252 kfree(characters[i]);
1255 memcpy(characters, default_chars, sizeof(default_chars));
1258 void reset_default_chartab(void)
1260 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1263 static const struct st_bits_data *pb_edit;
1265 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
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", msg_get(MSG_EDIT_DONE));
1272 special_handler = NULL;
1273 return 1;
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) ? msg_get(MSG_ON) :
1281 msg_get(MSG_OFF));
1282 return 1;
1285 /* Allocation concurrency is protected by the console semaphore */
1286 void speakup_allocate(struct vc_data *vc)
1288 int vc_num;
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;
1296 speakup_date(vc);
1297 } else if (!spk_parked)
1298 speakup_date(vc);
1301 void speakup_deallocate(struct vc_data *vc)
1303 int vc_num;
1305 vc_num = vc->vc_num;
1306 if (speakup_console[vc_num] != NULL) {
1307 kfree(speakup_console[vc_num]);
1308 speakup_console[vc_num] = NULL;
1312 static u_char is_cursor;
1313 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1314 static int cursor_con;
1316 static void reset_highlight_buffers(struct vc_data *);
1318 static int read_all_key;
1320 static void start_read_all_timer(struct vc_data *vc, int command);
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,
1334 static void kbd_fakekey2(struct vc_data *vc, int command)
1336 del_timer(&cursor_timer);
1337 speakup_fake_down_arrow();
1338 start_read_all_timer(vc, command);
1341 static void read_all_doc(struct vc_data *vc)
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 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);
1360 static void stop_read_all(struct vc_data *vc)
1362 del_timer(&cursor_timer);
1363 cursor_track = prev_cursor_track;
1364 spk_shut_up &= 0xfe;
1365 do_flush();
1368 static void start_read_all_timer(struct vc_data *vc, int command)
1370 struct var_t *cursor_timeout;
1372 cursor_con = vc->vc_num;
1373 read_all_key = command;
1374 cursor_timeout = get_var(CURSOR_TIME);
1375 mod_timer(&cursor_timer,
1376 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1379 static void handle_cursor_read_all(struct vc_data *vc, int command)
1381 int indcount, sentcount, rv, sn;
1383 switch (command) {
1384 case RA_NEXT_SENT:
1385 /* Get Current Sentence */
1386 get_index_count(&indcount, &sentcount);
1387 /*printk("%d %d ", indcount, sentcount); */
1388 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;
1394 synth_insert_next_index(0);
1395 } else {
1396 sn = 0;
1397 if (!say_sentence_num(sentcount + 1, 1)) {
1398 sn = 1;
1399 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;
1406 synth_insert_next_index(0);
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);
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);
1437 break;
1438 case RA_FIND_PREV_SENT:
1439 break;
1440 case RA_TIMER:
1441 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;
1450 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1452 unsigned long flags;
1453 spk_lock(flags);
1454 if (cursor_track == read_all_mode) {
1455 spk_parked &= 0xfe;
1456 if (synth == NULL || up_flag || spk_shut_up) {
1457 spk_unlock(flags);
1458 return NOTIFY_STOP;
1460 del_timer(&cursor_timer);
1461 spk_shut_up &= 0xfe;
1462 do_flush();
1463 start_read_all_timer(vc, value + 1);
1464 spk_unlock(flags);
1465 return NOTIFY_STOP;
1467 spk_unlock(flags);
1468 return NOTIFY_OK;
1471 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1473 unsigned long flags;
1474 struct var_t *cursor_timeout;
1476 spk_lock(flags);
1477 spk_parked &= 0xfe;
1478 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1479 spk_unlock(flags);
1480 return;
1482 spk_shut_up &= 0xfe;
1483 if (no_intr)
1484 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 = get_var(CURSOR_TIME);
1496 mod_timer(&cursor_timer,
1497 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1498 spk_unlock(flags);
1501 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1503 int i, bi, hi;
1504 int vc_num = vc->vc_num;
1506 bi = ((vc->vc_attr & 0x70) >> 4);
1507 hi = speakup_console[vc_num]->ht.highsize[bi];
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;
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++;
1527 i++;
1529 speakup_console[vc_num]->ht.highsize[bi] = hi;
1532 static void reset_highlight_buffers(struct vc_data *vc)
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;
1540 static int count_highlight_color(struct vc_data *vc)
1542 int i, bg;
1543 int cc;
1544 int vc_num = vc->vc_num;
1545 u16 ch;
1546 u16 *start = (u16 *) vc->vc_origin;
1548 for (i = 0; i < 8; i++)
1549 speakup_console[vc_num]->ht.bgcount[i] = 0;
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]++;
1559 start += vc->vc_size_row;
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;
1569 static int get_highlight_color(struct vc_data *vc)
1571 int i, j;
1572 unsigned int cptr[8], tmp;
1573 int vc_num = vc->vc_num;
1575 for (i = 0; i < 8; i++)
1576 cptr[i] = i;
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;
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;
1594 static int speak_highlight(struct vc_data *vc)
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 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;
1615 return 0;
1618 static void cursor_done(u_long data)
1620 struct vc_data *vc = vc_cons[cursor_con].d;
1621 unsigned long flags;
1622 del_timer(&cursor_timer);
1623 spk_lock(flags);
1624 if (cursor_con != fg_console) {
1625 is_cursor = 0;
1626 goto out;
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;
1636 if (cursor_track == read_all_mode) {
1637 handle_cursor_read_all(vc, read_all_key);
1638 goto out;
1640 if (cursor_track == CT_Highlight) {
1641 if (speak_highlight(vc)) {
1642 spk_keydown = is_cursor = 0;
1643 goto out;
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 spk_unlock(flags);
1657 /* called by: vt_notifier_call() */
1658 static void speakup_bs(struct vc_data *vc)
1660 unsigned long flags;
1661 if (!speakup_console[vc->vc_num])
1662 return;
1663 if (!spk_trylock(flags))
1664 /* Speakup output, discard */
1665 return;
1666 if (!spk_parked)
1667 speakup_date(vc);
1668 if (spk_shut_up || synth == NULL) {
1669 spk_unlock(flags);
1670 return;
1672 if (vc->vc_num == fg_console && spk_keydown) {
1673 spk_keydown = 0;
1674 if (!is_cursor)
1675 say_char(vc);
1677 spk_unlock(flags);
1680 /* called by: vt_notifier_call() */
1681 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1683 unsigned long flags;
1684 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1685 return;
1686 if (!spk_trylock(flags))
1687 /* Speakup output, discard */
1688 return;
1689 if (bell_pos && spk_keydown && (vc->vc_x == 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 spk_unlock(flags);
1695 return;
1697 if (win_enabled) {
1698 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1699 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1700 spk_unlock(flags);
1701 return;
1705 spkup_write(str, len);
1706 spk_unlock(flags);
1709 void speakup_con_update(struct vc_data *vc)
1711 unsigned long flags;
1712 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1713 return;
1714 if (!spk_trylock(flags))
1715 /* Speakup output, discard */
1716 return;
1717 speakup_date(vc);
1718 spk_unlock(flags);
1721 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1723 unsigned long flags;
1724 int on_off = 2;
1725 char *label;
1726 if (synth == NULL || up_flag || spk_killed)
1727 return;
1728 spk_lock(flags);
1729 spk_shut_up &= 0xfe;
1730 if (no_intr)
1731 do_flush();
1732 switch (value) {
1733 case KVAL(K_CAPS):
1734 label = msg_get(MSG_KEYNAME_CAPSLOCK);
1735 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK));
1736 break;
1737 case KVAL(K_NUM):
1738 label = msg_get(MSG_KEYNAME_NUMLOCK);
1739 on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK));
1740 break;
1741 case KVAL(K_HOLD):
1742 label = msg_get(MSG_KEYNAME_SCROLLLOCK);
1743 on_off = (vc_kbd_led(kbd_table + vc->vc_num, 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 spk_unlock(flags);
1750 return;
1752 if (on_off < 2)
1753 synth_printf("%s %s\n",
1754 label, msg_get(MSG_STATUS_START + on_off));
1755 spk_unlock(flags);
1758 static int inc_dec_var(u_char value)
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 = 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 (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;
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;
1790 static void speakup_win_set(struct vc_data *vc)
1792 char info[40];
1793 if (win_start > 1) {
1794 synth_printf("%s\n", msg_get(MSG_WINDOW_ALREADY_SET));
1795 return;
1797 if (spk_x < win_left || spk_y < win_top) {
1798 synth_printf("%s\n", msg_get(MSG_END_BEFORE_START));
1799 return;
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), 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;
1815 snprintf(info, sizeof(info), msg_get(MSG_WINDOW_BOUNDARY),
1816 (win_start) ? msg_get(MSG_END) : msg_get(MSG_START),
1817 (int)spk_y + 1, (int)spk_x + 1);
1819 synth_printf("%s\n", info);
1820 win_start++;
1823 static void speakup_win_clear(struct vc_data *vc)
1825 win_top = win_bottom = 0;
1826 win_left = win_right = 0;
1827 win_start = 0;
1828 synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED));
1831 static void speakup_win_enable(struct vc_data *vc)
1833 if (win_start < 2) {
1834 synth_printf("%s\n", msg_get(MSG_NO_WINDOW));
1835 return;
1837 win_enabled ^= 1;
1838 if (win_enabled)
1839 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED));
1840 else
1841 synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED));
1844 static void speakup_bits(struct vc_data *vc)
1846 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1847 if (special_handler != NULL || val < 1 || val > 6) {
1848 synth_printf("%s\n", msg_get(MSG_ERROR));
1849 return;
1851 pb_edit = &punc_info[val];
1852 synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1853 special_handler = edit_bits;
1856 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1858 static u_char *goto_buf = "\0\0\0\0\0\0";
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;
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", msg_get(MSG_GOTO_CANCELED));
1892 goto_buf[num = 0] = '\0';
1893 special_handler = NULL;
1894 return 1;
1896 cp = speakup_s2i(goto_buf, &go_pos);
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;
1919 goto_buf[num = 0] = '\0';
1920 do_goto:
1921 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);
1933 return 1;
1936 static void speakup_goto(struct vc_data *vc)
1938 if (special_handler != NULL) {
1939 synth_printf("%s\n", msg_get(MSG_ERROR));
1940 return;
1942 synth_printf("%s\n", msg_get(MSG_GOTO));
1943 special_handler = handle_goto;
1944 return;
1947 static void speakup_help(struct vc_data *vc)
1949 handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1952 static void do_nothing(struct vc_data *vc)
1954 return; /* flush done in do_spkup */
1957 static u_char key_speakup, spk_key_locked;
1959 static void speakup_lock(struct vc_data *vc)
1961 if (!spk_key_locked)
1962 spk_key_locked = key_speakup = 16;
1963 else
1964 spk_key_locked = key_speakup = 0;
1967 typedef void (*spkup_hand) (struct vc_data *);
1968 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
1987 static void do_spkup(struct vc_data *vc, u_char value)
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 do_flush();
1997 (*spkup_handler[value]) (vc);
1998 } else {
1999 if (inc_dec_var(value) < 0)
2000 bleep(9);
2004 static const char *pad_chars = "0123456789+-*/\015,.?()";
2007 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2008 int up_flag)
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;
2019 spk_lock(flags);
2020 tty = vc->port.tty;
2021 if (type >= 0xf0)
2022 type -= 0xf0;
2023 if (type == KT_PAD
2024 && (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) {
2025 if (up_flag) {
2026 spk_keydown = 0;
2027 goto out;
2029 value = spk_lastkey = pad_chars[value];
2030 spk_keydown++;
2031 spk_parked &= 0xfe;
2032 goto no_map;
2034 if (keycode >= MAX_KEY)
2035 goto no_map;
2036 key_info = our_keys[keycode];
2037 if (key_info == 0)
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;
2054 shift_info = (shift_state & 0x0f) + key_speakup;
2055 offset = 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 do_flush();
2067 goto out;
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 = shift_table[shift_info + 32];
2075 /* double press? */
2076 if (offset && key_info[offset])
2077 new_key = key_info[offset];
2079 last_keycode = keycode;
2080 last_spk_jiffy = jiffies;
2081 type = KT_SPKUP;
2082 value = new_key;
2085 no_map:
2086 if (type == KT_SPKUP && special_handler == NULL) {
2087 do_spkup(vc, new_key);
2088 spk_close_press = 0;
2089 ret = 1;
2090 goto out;
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 (!no_intr)
2101 do_flush();
2102 if (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 = (*special_handler) (vc, type, value, keycode);
2111 spk_close_press = 0;
2112 if (ret < 0)
2113 bleep(9);
2114 goto out;
2116 last_keycode = 0;
2117 out:
2118 spk_unlock(flags);
2119 return ret;
2122 static int keyboard_notifier_call(struct notifier_block *nb,
2123 unsigned long code, void *_param)
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 */
2131 if (vc->vc_mode == KD_GRAPHICS)
2132 return ret;
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.
2143 if (speakup_fake_key_pressed())
2144 return ret;
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;
2181 break;
2184 return ret;
2187 static int vt_notifier_call(struct notifier_block *nb,
2188 unsigned long code, void *_param)
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);
2207 break;
2208 case VT_UPDATE:
2209 speakup_con_update(vc);
2210 break;
2212 return NOTIFY_OK;
2215 /* called by: module_exit() */
2216 static void __exit speakup_exit(void)
2218 int i;
2220 free_user_msgs();
2221 unregister_keyboard_notifier(&keyboard_notifier_block);
2222 unregister_vt_notifier(&vt_notifier_block);
2223 speakup_unregister_devsynth();
2224 del_timer(&cursor_timer);
2226 kthread_stop(speakup_task);
2227 speakup_task = NULL;
2228 mutex_lock(&spk_mutex);
2229 synth_release();
2230 mutex_unlock(&spk_mutex);
2232 for (i = 0; i < MAXVARS; i++)
2233 speakup_unregister_var(i);
2235 for (i = 0; i < 256; i++) {
2236 if (characters[i] != default_chars[i])
2237 kfree(characters[i]);
2239 for (i = 0; speakup_console[i]; i++)
2240 kfree(speakup_console[i]);
2241 speakup_kobj_exit();
2242 speakup_remove_virtual_keyboard();
2245 /* call by: module_init() */
2246 static int __init speakup_init(void)
2248 int i;
2249 int err;
2250 struct st_spk_t *first_console;
2251 struct vc_data *vc = vc_cons[fg_console].d;
2252 struct var_t *var;
2254 err = speakup_add_virtual_keyboard();
2255 if (err)
2256 goto out;
2258 initialize_msgs(); /* Initialize arrays for i18n. */
2259 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2260 if (!first_console) {
2261 err = -ENOMEM;
2262 goto err_cons;
2264 err = speakup_kobj_init();
2265 if (err)
2266 goto err_kobject;
2268 reset_default_chars();
2269 reset_default_chartab();
2271 speakup_console[vc->vc_num] = first_console;
2272 speakup_date(vc);
2273 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2275 strlwr(synth_name);
2276 spk_vars[0].u.n.high = vc->vc_cols;
2277 for (var = spk_vars; var->var_id != MAXVARS; var++)
2278 speakup_register_var(var);
2279 for (var = synth_time_vars;
2280 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2281 speakup_register_var(var);
2282 for (i = 1; punc_info[i].mask != 0; i++)
2283 set_mask_bits(0, i, 2);
2285 set_key_info(key_defaults, key_buf);
2286 if (quiet_boot)
2287 spk_shut_up |= 0x01;
2289 for (i = 0; i < MAX_NR_CONSOLES; i++)
2290 if (vc_cons[i].d)
2291 speakup_allocate(vc_cons[i].d);
2293 pr_warn("synth name on entry is: %s\n", synth_name);
2294 synth_init(synth_name);
2295 speakup_register_devsynth();
2297 register_keyboard_notifier(&keyboard_notifier_block);
2298 register_vt_notifier(&vt_notifier_block);
2300 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2301 set_user_nice(speakup_task, 10);
2302 if (IS_ERR(speakup_task)) {
2303 err = -ENOMEM;
2304 goto err_kobject;
2306 wake_up_process(speakup_task);
2307 goto out;
2309 err_kobject:
2310 speakup_kobj_exit();
2311 kfree(first_console);
2312 err_cons:
2313 speakup_remove_virtual_keyboard();
2314 out:
2315 return err;
2318 module_init(speakup_init);
2319 module_exit(speakup_exit);