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