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.
21 #include <linux/kernel.h>
23 #include <linux/tty.h>
24 #include <linux/mm.h> /* __get_free_page() and friends */
25 #include <linux/vt_kern.h>
26 #include <linux/ctype.h>
27 #include <linux/selection.h>
28 #include <linux/unistd.h>
29 #include <linux/jiffies.h>
30 #include <linux/kthread.h>
31 #include <linux/keyboard.h> /* for KT_SHIFT */
32 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
33 #include <linux/input.h>
34 #include <linux/kmod.h>
36 /* speakup_*_selection */
37 #include <linux/module.h>
38 #include <linux/sched.h>
39 #include <linux/slab.h>
40 #include <linux/types.h>
41 #include <linux/consolemap.h>
43 #include <linux/spinlock.h>
44 #include <linux/notifier.h>
46 #include <linux/uaccess.h> /* copy_from|to|user() and others */
51 #define MAX_DELAY msecs_to_jiffies(500)
52 #define MINECHOCHAR SPACE
54 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
55 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
56 MODULE_DESCRIPTION("Speakup console speech");
57 MODULE_LICENSE("GPL");
58 MODULE_VERSION(SPEAKUP_VERSION);
61 module_param_named(synth, synth_name, charp, S_IRUGO);
62 module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
64 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
65 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
67 special_func spk_special_handler;
69 short spk_pitch_shift, synth_flags;
71 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
72 int spk_no_intr, spk_spell_delay;
73 int spk_key_echo, spk_say_word_ctl;
74 int spk_say_ctrl, spk_bell_pos;
76 int spk_punc_level, spk_reading_punc;
77 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
78 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
79 const struct st_bits_data spk_punc_info[] = {
81 {"some", "/$%&@", SOME},
82 {"most", "$%&#()=+*/@^<>|\\", MOST},
83 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
84 {"delimiters", "", B_WDLM},
85 {"repeats", "()", CH_RPT},
86 {"extended numeric", "", B_EXNUM},
87 {"symbols", "", B_SYM},
91 static char mark_cut_flag;
93 static u_char *spk_shift_table;
94 u_char *spk_our_keys[MAX_KEY];
95 u_char spk_key_buf[600];
96 const u_char spk_key_defaults[] = {
97 #include "speakupmap.h"
100 /* Speakup Cursor Track Variables */
101 static int cursor_track = 1, prev_cursor_track = 1;
103 /* cursor track modes, must be ordered same as cursor_msgs */
111 #define read_all_mode CT_Max
113 static struct tty_struct *tty;
115 static void spkup_write(const char *in_buf, int count);
117 static char *phonetic[] = {
118 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
119 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
121 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
122 "x ray", "yankee", "zulu"
125 /* array of 256 char pointers (one for each character description)
126 * initialized to default_chars and user selectable via
127 * /proc/speakup/characters
129 char *spk_characters[256];
131 char *spk_default_chars[256] = {
132 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
133 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
134 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
135 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
137 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
139 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
142 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
144 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
145 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
146 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
147 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
148 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
151 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
152 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
153 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
154 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
155 /*127*/ "del", "control", "control", "control", "control", "control",
156 "control", "control", "control", "control", "control",
157 /*138*/ "control", "control", "control", "control", "control",
158 "control", "control", "control", "control", "control",
159 "control", "control",
160 /*150*/ "control", "control", "control", "control", "control",
161 "control", "control", "control", "control", "control",
162 /*160*/ "nbsp", "inverted bang",
163 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
164 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
165 /*172*/ "not", "soft hyphen", "registered", "macron",
166 /*176*/ "degrees", "plus or minus", "super two", "super three",
167 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
168 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
169 /*188*/ "one quarter", "one half", "three quarters",
171 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
173 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
175 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
177 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
178 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
180 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
181 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
182 /*230*/ "ae", "c cidella", "e grave", "e acute",
183 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
185 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
187 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
189 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
192 /* array of 256 u_short (one for each character)
193 * initialized to default_chartab and user selectable via
194 * /sys/module/speakup/parameters/chartab
196 u_short spk_chartab[256];
198 static u_short default_chartab[256] = {
199 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
200 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
201 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
202 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
203 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
204 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
205 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
206 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
207 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
208 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
209 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
210 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
211 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
212 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
213 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
214 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
215 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
217 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
219 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
221 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
223 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
225 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
226 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
227 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
228 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
229 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
230 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
231 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
232 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
233 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
234 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
235 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
238 struct task_struct *speakup_task;
239 struct bleep spk_unprocessed_sound;
240 static int spk_keydown;
241 static u_char spk_lastkey, spk_close_press, keymap_flags;
242 static u_char last_keycode, this_speakup_key;
243 static u_long last_spk_jiffy;
245 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
247 DEFINE_MUTEX(spk_mutex);
249 static int keyboard_notifier_call(struct notifier_block *,
250 unsigned long code, void *param);
252 static struct notifier_block keyboard_notifier_block = {
253 .notifier_call = keyboard_notifier_call,
256 static int vt_notifier_call(struct notifier_block *,
257 unsigned long code, void *param);
259 static struct notifier_block vt_notifier_block = {
260 .notifier_call = vt_notifier_call,
263 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
265 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
266 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 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(vc, (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
284 int time = spk_bleep_time;
286 freq = vals[val % 12];
288 freq *= (1 << (val / 12));
289 spk_unprocessed_sound.freq = freq;
290 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
291 spk_unprocessed_sound.active = 1;
292 /* We can only have 1 active sound at a time. */
295 static void speakup_shut_up(struct vc_data *vc)
306 static void speech_kill(struct vc_data *vc)
308 char val = synth->is_alive(synth);
313 /* re-enables synth, if disabled */
314 if (val == 2 || spk_killed) {
316 spk_shut_up &= ~0x40;
317 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
319 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
324 static void speakup_off(struct vc_data *vc)
326 if (spk_shut_up & 0x80) {
328 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
331 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
336 static void speakup_parked(struct vc_data *vc)
338 if (spk_parked & 0x80) {
340 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
343 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
347 static void speakup_cut(struct vc_data *vc)
349 static const char err_buf[] = "set selection failed";
352 if (!mark_cut_flag) {
354 spk_xs = (u_short) spk_x;
355 spk_ys = (u_short) spk_y;
357 synth_printf("%s\n", spk_msg_get(MSG_MARK));
360 spk_xe = (u_short) spk_x;
361 spk_ye = (u_short) spk_y;
363 synth_printf("%s\n", spk_msg_get(MSG_CUT));
365 speakup_clear_selection();
366 ret = speakup_set_selection(tty);
370 break; /* no error */
372 pr_warn("%sEFAULT\n", err_buf);
375 pr_warn("%sEINVAL\n", err_buf);
378 pr_warn("%sENOMEM\n", err_buf);
383 static void speakup_paste(struct vc_data *vc)
387 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
389 synth_printf("%s\n", spk_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;
400 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
403 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
405 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
408 synth_printf(" %s ", spk_msg_get(MSG_ON));
409 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
420 static void announce_edge(struct vc_data *vc, int msg_id)
424 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
426 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
429 static void speak_char(u_char ch)
431 char *cp = spk_characters[ch];
432 struct var_t *direct = spk_get_var(DIRECT);
434 if (direct && direct->u.n.value) {
435 if (IS_CHAR(ch, B_CAP)) {
437 synth_printf("%s", spk_str_caps_start);
439 synth_printf("%c", ch);
440 if (IS_CHAR(ch, B_CAP))
441 synth_printf("%s", spk_str_caps_stop);
445 pr_info("speak_char: cp == NULL!\n");
448 synth_buffer_add(SPACE);
449 if (IS_CHAR(ch, B_CAP)) {
451 synth_printf("%s", spk_str_caps_start);
452 synth_printf("%s", cp);
453 synth_printf("%s", spk_str_caps_stop);
456 synth_printf("%s", spk_msg_get(MSG_CTRL));
459 synth_printf("%s", cp);
461 synth_buffer_add(SPACE);
464 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
472 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
476 if (w & vc->vc_hi_font_mask) {
477 w &= ~vc->vc_hi_font_mask;
481 ch = inverse_translate(vc, c, 0);
482 *attribs = (w & 0xff00) >> 8;
487 static void say_char(struct vc_data *vc)
491 spk_old_attr = spk_attr;
492 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
493 if (spk_attr != spk_old_attr) {
494 if (spk_attrib_bleep & 1)
496 if (spk_attrib_bleep & 2)
499 speak_char(ch & 0xff);
502 static void say_phonetic_char(struct vc_data *vc)
506 spk_old_attr = spk_attr;
507 ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
508 if (isascii(ch) && isalpha(ch)) {
510 synth_printf("%s\n", phonetic[--ch]);
512 if (IS_CHAR(ch, B_NUM))
513 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
518 static void say_prev_char(struct vc_data *vc)
522 announce_edge(vc, edge_left);
530 static void say_next_char(struct vc_data *vc)
533 if (spk_x == vc->vc_cols - 1) {
534 announce_edge(vc, edge_right);
542 /* get_word - will first check to see if the character under the
543 * reading cursor is a space and if spk_say_word_ctl is true it will
544 * return the word space. If spk_say_word_ctl is not set it will check to
545 * see if there is a word starting on the next position to the right
546 * and return that word if it exists. If it does not exist it will
547 * move left to the beginning of any previous word on the line or the
548 * beginning off the line whichever comes first..
551 static u_long get_word(struct vc_data *vc)
553 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
558 spk_old_attr = spk_attr;
559 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
561 /* decided to take out the sayword if on a space (mis-information */
562 if (spk_say_word_ctl && ch == SPACE) {
564 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
566 } else if ((tmpx < vc->vc_cols - 2)
567 && (ch == SPACE || ch == 0 || IS_WDLM(ch))
568 && ((char)get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE)) {
573 ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
574 if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
575 && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
581 attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
582 buf[cnt++] = attr_ch & 0xff;
583 while (tmpx < vc->vc_cols - 1) {
586 ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
587 if ((ch == SPACE) || ch == 0
588 || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
596 static void say_word(struct vc_data *vc)
598 u_long cnt = get_word(vc);
599 u_short saved_punc_mask = spk_punc_mask;
603 spk_punc_mask = PUNC;
605 spkup_write(buf, cnt);
606 spk_punc_mask = saved_punc_mask;
609 static void say_prev_word(struct vc_data *vc)
613 u_short edge_said = 0, last_state = 0, state = 0;
619 announce_edge(vc, edge_top);
624 edge_said = edge_quiet;
629 edge_said = edge_top;
632 if (edge_said != edge_quiet)
633 edge_said = edge_left;
637 spk_x = vc->vc_cols - 1;
641 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
642 if (ch == SPACE || ch == 0)
644 else if (IS_WDLM(ch))
648 if (state < last_state) {
655 if (spk_x == 0 && edge_said == edge_quiet)
656 edge_said = edge_left;
657 if (edge_said > 0 && edge_said < edge_quiet)
658 announce_edge(vc, edge_said);
662 static void say_next_word(struct vc_data *vc)
666 u_short edge_said = 0, last_state = 2, state = 0;
669 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
670 announce_edge(vc, edge_bottom);
674 ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
675 if (ch == SPACE || ch == 0)
677 else if (IS_WDLM(ch))
681 if (state > last_state)
683 if (spk_x >= vc->vc_cols - 1) {
684 if (spk_y == vc->vc_rows - 1) {
685 edge_said = edge_bottom;
691 edge_said = edge_right;
698 announce_edge(vc, edge_said);
702 static void spell_word(struct vc_data *vc)
704 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
705 char *cp = buf, *str_cap = spk_str_caps_stop;
706 char *cp1, *last_cap = spk_str_caps_stop;
711 while ((ch = (u_char) *cp)) {
713 synth_printf(" %s ", delay_str[spk_spell_delay]);
714 if (IS_CHAR(ch, B_CAP)) {
715 str_cap = spk_str_caps_start;
716 if (*spk_str_caps_stop)
718 else /* synth has no pitch */
719 last_cap = spk_str_caps_stop;
721 str_cap = spk_str_caps_stop;
722 if (str_cap != last_cap) {
723 synth_printf("%s", str_cap);
726 if (this_speakup_key == SPELL_PHONETIC
727 && (isascii(ch) && isalpha(ch))) {
729 cp1 = phonetic[--ch];
731 cp1 = spk_characters[ch];
733 synth_printf("%s", spk_msg_get(MSG_CTRL));
737 synth_printf("%s", cp1);
740 if (str_cap != spk_str_caps_stop)
741 synth_printf("%s", spk_str_caps_stop);
744 static int get_line(struct vc_data *vc)
746 u_long tmp = spk_pos - (spk_x * 2);
750 spk_old_attr = spk_attr;
751 spk_attr = get_attributes(vc, (u_short *)spk_pos);
752 for (i = 0; i < vc->vc_cols; i++) {
753 buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
756 for (--i; i >= 0; i--)
762 static void say_line(struct vc_data *vc)
764 int i = get_line(vc);
766 u_short saved_punc_mask = spk_punc_mask;
769 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
773 if (this_speakup_key == SAY_LINE_INDENT) {
777 synth_printf("%d, ", (cp - buf) + 1);
779 spk_punc_mask = spk_punc_masks[spk_reading_punc];
781 spk_punc_mask = saved_punc_mask;
784 static void say_prev_line(struct vc_data *vc)
788 announce_edge(vc, edge_top);
792 spk_pos -= vc->vc_size_row;
796 static void say_next_line(struct vc_data *vc)
799 if (spk_y == vc->vc_rows - 1) {
800 announce_edge(vc, edge_bottom);
804 spk_pos += vc->vc_size_row;
808 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
813 u_short saved_punc_mask = spk_punc_mask;
815 spk_old_attr = spk_attr;
816 spk_attr = get_attributes(vc, (u_short *)from);
818 buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
820 if (i >= vc->vc_size_row)
823 for (--i; i >= 0; i--)
831 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
834 spk_punc_mask = saved_punc_mask;
838 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
841 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
842 u_long end = start + (to * 2);
845 if (say_from_to(vc, start, end, read_punc) <= 0)
846 if (cursor_track != read_all_mode)
847 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
850 /* Sentence Reading Commands */
852 static int currsentence;
853 static int numsentences[2];
854 static char *sentbufend[2];
855 static char *sentmarks[2][10];
858 static char sentbuf[2][256];
860 static int say_sentence_num(int num, int prev)
863 currsentence = num + 1;
864 if (prev && --bn == -1)
867 if (num > numsentences[bn])
870 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
874 static int get_sentence_buf(struct vc_data *vc, int read_punc)
884 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
885 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
887 numsentences[bn] = 0;
888 sentmarks[bn][0] = &sentbuf[bn][0];
890 spk_old_attr = spk_attr;
891 spk_attr = get_attributes(vc, (u_short *)start);
893 while (start < end) {
894 sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
896 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
897 && numsentences[bn] < 9) {
898 /* Sentence Marker */
900 sentmarks[bn][numsentences[bn]] =
906 if (i >= vc->vc_size_row)
910 for (--i; i >= 0; i--)
911 if (sentbuf[bn][i] != SPACE)
917 sentbuf[bn][++i] = SPACE;
918 sentbuf[bn][++i] = '\0';
920 sentbufend[bn] = &sentbuf[bn][i];
921 return numsentences[bn];
924 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
926 u_long start = vc->vc_origin, end;
929 start += from * vc->vc_size_row;
930 if (to > vc->vc_rows)
932 end = vc->vc_origin + (to * vc->vc_size_row);
933 for (from = start; from < end; from = to) {
934 to = from + vc->vc_size_row;
935 say_from_to(vc, from, to, 1);
939 static void say_screen(struct vc_data *vc)
941 say_screen_from_to(vc, 0, vc->vc_rows);
944 static void speakup_win_say(struct vc_data *vc)
946 u_long start, end, from, to;
949 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
952 start = vc->vc_origin + (win_top * vc->vc_size_row);
953 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
954 while (start <= end) {
955 from = start + (win_left * 2);
956 to = start + (win_right * 2);
957 say_from_to(vc, from, to, 1);
958 start += vc->vc_size_row;
962 static void top_edge(struct vc_data *vc)
965 spk_pos = vc->vc_origin + 2 * spk_x;
970 static void bottom_edge(struct vc_data *vc)
973 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
974 spk_y = vc->vc_rows - 1;
978 static void left_edge(struct vc_data *vc)
981 spk_pos -= spk_x * 2;
986 static void right_edge(struct vc_data *vc)
989 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
990 spk_x = vc->vc_cols - 1;
994 static void say_first_char(struct vc_data *vc)
996 int i, len = get_line(vc);
1001 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1004 for (i = 0; i < len; i++)
1005 if (buf[i] != SPACE)
1008 spk_pos -= (spk_x - i) * 2;
1010 synth_printf("%d, ", ++i);
1014 static void say_last_char(struct vc_data *vc)
1016 int len = get_line(vc);
1021 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1025 spk_pos -= (spk_x - len) * 2;
1027 synth_printf("%d, ", ++len);
1031 static void say_position(struct vc_data *vc)
1033 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1038 /* Added by brianb */
1039 static void say_char_num(struct vc_data *vc)
1042 u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1045 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1048 /* these are stub functions to keep keyboard.c happy. */
1050 static void say_from_top(struct vc_data *vc)
1052 say_screen_from_to(vc, 0, spk_y);
1055 static void say_to_bottom(struct vc_data *vc)
1057 say_screen_from_to(vc, spk_y, vc->vc_rows);
1060 static void say_from_left(struct vc_data *vc)
1062 say_line_from_to(vc, 0, spk_x, 1);
1065 static void say_to_right(struct vc_data *vc)
1067 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1070 /* end of stub functions. */
1072 static void spkup_write(const char *in_buf, int count)
1074 static int rep_count;
1075 static u_char ch = '\0', old_ch = '\0';
1076 static u_short char_type, last_type;
1077 int in_count = count;
1081 if (cursor_track == read_all_mode) {
1082 /* Insert Sentence Index */
1083 if ((in_buf == sentmarks[bn][currsentence]) &&
1084 (currsentence <= numsentences[bn]))
1085 synth_insert_next_index(currsentence++);
1087 ch = (u_char) *in_buf++;
1088 char_type = spk_chartab[ch];
1089 if (ch == old_ch && !(char_type & B_NUM)) {
1090 if (++rep_count > 2)
1093 if ((last_type & CH_RPT) && rep_count > 2) {
1095 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1101 if (ch == spk_lastkey) {
1103 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1105 } else if (char_type & B_ALPHA) {
1106 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1107 synth_buffer_add(SPACE);
1108 synth_printf("%c", ch);
1109 } else if (char_type & B_NUM) {
1111 synth_printf("%c", ch);
1112 } else if (char_type & spk_punc_mask) {
1114 char_type &= ~PUNC; /* for dec nospell processing */
1115 } else if (char_type & SYNTH_OK) {
1116 /* these are usually puncts like . and , which synth
1117 * needs for expression.
1118 * suppress multiple to get rid of long pauses and
1119 * clear repeat count
1121 * repeats on you don't get nothing repeated count
1124 synth_printf("%c", ch);
1128 /* send space and record position, if next is num overwrite space */
1130 synth_buffer_add(SPACE);
1135 last_type = char_type;
1138 if (in_count > 2 && rep_count > 2) {
1139 if (last_type & CH_RPT) {
1141 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1149 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1151 static void read_all_doc(struct vc_data *vc);
1152 static void cursor_done(u_long data);
1153 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1155 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1157 unsigned long flags;
1159 if (synth == NULL || up_flag || spk_killed)
1161 spin_lock_irqsave(&speakup_info.spinlock, flags);
1162 if (cursor_track == read_all_mode) {
1165 del_timer(&cursor_timer);
1166 spk_shut_up &= 0xfe;
1171 del_timer(&cursor_timer);
1172 cursor_track = prev_cursor_track;
1173 spk_shut_up &= 0xfe;
1178 spk_shut_up &= 0xfe;
1181 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1182 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1183 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1186 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1188 unsigned long flags;
1190 spin_lock_irqsave(&speakup_info.spinlock, flags);
1194 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1197 if (synth == NULL || spk_killed) {
1198 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1201 spk_shut_up &= 0xfe;
1202 spk_lastkey = value;
1205 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1207 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1210 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1212 int i = 0, states, key_data_len;
1213 const u_char *cp = key_info;
1214 u_char *cp1 = k_buffer;
1215 u_char ch, version, num_keys;
1218 if (version != KEY_MAP_VER)
1221 states = (int)cp[1];
1222 key_data_len = (states + 1) * (num_keys + 1);
1223 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1225 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1226 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1227 spk_shift_table = k_buffer;
1228 spk_our_keys[0] = spk_shift_table;
1229 cp1 += SHIFT_TBL_SIZE;
1230 memcpy(cp1, cp, key_data_len + 3);
1231 /* get num_keys, states and data */
1232 cp1 += 2; /* now pointing at shift states */
1233 for (i = 1; i <= states; i++) {
1235 if (ch >= SHIFT_TBL_SIZE)
1237 spk_shift_table[ch] = i;
1239 keymap_flags = *cp1++;
1240 while ((ch = *cp1)) {
1243 spk_our_keys[ch] = cp1;
1249 static struct var_t spk_vars[] = {
1250 /* bell must be first to set high limit */
1251 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1252 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1253 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1254 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1255 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1256 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1257 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1258 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1259 {SAY_CONTROL, TOGGLE_0},
1260 {SAY_WORD_CTL, TOGGLE_0},
1261 {NO_INTERRUPT, TOGGLE_0},
1262 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1266 static void toggle_cursoring(struct vc_data *vc)
1268 if (cursor_track == read_all_mode)
1269 cursor_track = prev_cursor_track;
1270 if (++cursor_track >= CT_Max)
1272 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1275 void spk_reset_default_chars(void)
1279 /* First, free any non-default */
1280 for (i = 0; i < 256; i++) {
1281 if ((spk_characters[i] != NULL)
1282 && (spk_characters[i] != spk_default_chars[i]))
1283 kfree(spk_characters[i]);
1286 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1289 void spk_reset_default_chartab(void)
1291 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1294 static const struct st_bits_data *pb_edit;
1296 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1298 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1300 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1303 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1304 spk_special_handler = NULL;
1307 if (mask < PUNC && !(ch_type & PUNC))
1309 spk_chartab[ch] ^= mask;
1311 synth_printf(" %s\n",
1312 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1313 spk_msg_get(MSG_OFF));
1317 /* Allocation concurrency is protected by the console semaphore */
1318 static int speakup_allocate(struct vc_data *vc)
1322 vc_num = vc->vc_num;
1323 if (speakup_console[vc_num] == NULL) {
1324 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1326 if (speakup_console[vc_num] == NULL)
1329 } else if (!spk_parked)
1335 static void speakup_deallocate(struct vc_data *vc)
1339 vc_num = vc->vc_num;
1340 kfree(speakup_console[vc_num]);
1341 speakup_console[vc_num] = NULL;
1344 static u_char is_cursor;
1345 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1346 static int cursor_con;
1348 static void reset_highlight_buffers(struct vc_data *);
1350 static int read_all_key;
1352 static void start_read_all_timer(struct vc_data *vc, int command);
1366 static void kbd_fakekey2(struct vc_data *vc, int command)
1368 del_timer(&cursor_timer);
1369 speakup_fake_down_arrow();
1370 start_read_all_timer(vc, command);
1373 static void read_all_doc(struct vc_data *vc)
1375 if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1377 if (!synth_supports_indexing())
1379 if (cursor_track != read_all_mode)
1380 prev_cursor_track = cursor_track;
1381 cursor_track = read_all_mode;
1382 spk_reset_index_count(0);
1383 if (get_sentence_buf(vc, 0) == -1)
1384 kbd_fakekey2(vc, RA_DOWN_ARROW);
1386 say_sentence_num(0, 0);
1387 synth_insert_next_index(0);
1388 start_read_all_timer(vc, RA_TIMER);
1392 static void stop_read_all(struct vc_data *vc)
1394 del_timer(&cursor_timer);
1395 cursor_track = prev_cursor_track;
1396 spk_shut_up &= 0xfe;
1400 static void start_read_all_timer(struct vc_data *vc, int command)
1402 struct var_t *cursor_timeout;
1404 cursor_con = vc->vc_num;
1405 read_all_key = command;
1406 cursor_timeout = spk_get_var(CURSOR_TIME);
1407 mod_timer(&cursor_timer,
1408 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1411 static void handle_cursor_read_all(struct vc_data *vc, int command)
1413 int indcount, sentcount, rv, sn;
1417 /* Get Current Sentence */
1418 spk_get_index_count(&indcount, &sentcount);
1419 /*printk("%d %d ", indcount, sentcount); */
1420 spk_reset_index_count(sentcount + 1);
1421 if (indcount == 1) {
1422 if (!say_sentence_num(sentcount + 1, 0)) {
1423 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1426 synth_insert_next_index(0);
1429 if (!say_sentence_num(sentcount + 1, 1)) {
1431 spk_reset_index_count(sn);
1433 synth_insert_next_index(0);
1434 if (!say_sentence_num(sn, 0)) {
1435 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1438 synth_insert_next_index(0);
1440 start_read_all_timer(vc, RA_TIMER);
1450 if (get_sentence_buf(vc, 0) == -1) {
1451 kbd_fakekey2(vc, RA_DOWN_ARROW);
1453 say_sentence_num(0, 0);
1454 synth_insert_next_index(0);
1455 start_read_all_timer(vc, RA_TIMER);
1458 case RA_FIND_NEXT_SENT:
1459 rv = get_sentence_buf(vc, 0);
1463 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1465 say_sentence_num(1, 0);
1466 synth_insert_next_index(0);
1467 start_read_all_timer(vc, RA_TIMER);
1470 case RA_FIND_PREV_SENT:
1473 spk_get_index_count(&indcount, &sentcount);
1475 kbd_fakekey2(vc, RA_DOWN_ARROW);
1477 start_read_all_timer(vc, RA_TIMER);
1482 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1484 unsigned long flags;
1486 spin_lock_irqsave(&speakup_info.spinlock, flags);
1487 if (cursor_track == read_all_mode) {
1489 if (synth == NULL || up_flag || spk_shut_up) {
1490 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1493 del_timer(&cursor_timer);
1494 spk_shut_up &= 0xfe;
1496 start_read_all_timer(vc, value + 1);
1497 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1500 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1504 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1506 unsigned long flags;
1507 struct var_t *cursor_timeout;
1509 spin_lock_irqsave(&speakup_info.spinlock, flags);
1511 if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1512 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1515 spk_shut_up &= 0xfe;
1518 /* the key press flushes if !no_inter but we want to flush on cursor
1519 * moves regardless of no_inter state
1521 is_cursor = value + 1;
1522 old_cursor_pos = vc->vc_pos;
1523 old_cursor_x = vc->vc_x;
1524 old_cursor_y = vc->vc_y;
1525 speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1526 cursor_con = vc->vc_num;
1527 if (cursor_track == CT_Highlight)
1528 reset_highlight_buffers(vc);
1529 cursor_timeout = spk_get_var(CURSOR_TIME);
1530 mod_timer(&cursor_timer,
1531 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1532 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1535 static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1538 int vc_num = vc->vc_num;
1540 bi = (vc->vc_attr & 0x70) >> 4;
1541 hi = speakup_console[vc_num]->ht.highsize[bi];
1544 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1545 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1546 speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1547 speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1549 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1550 if ((ic[i] > 32) && (ic[i] < 127)) {
1551 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1553 } else if ((ic[i] == 32) && (hi != 0)) {
1554 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1556 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1563 speakup_console[vc_num]->ht.highsize[bi] = hi;
1566 static void reset_highlight_buffers(struct vc_data *vc)
1569 int vc_num = vc->vc_num;
1571 for (i = 0; i < 8; i++)
1572 speakup_console[vc_num]->ht.highsize[i] = 0;
1575 static int count_highlight_color(struct vc_data *vc)
1579 int vc_num = vc->vc_num;
1581 u16 *start = (u16 *) vc->vc_origin;
1583 for (i = 0; i < 8; i++)
1584 speakup_console[vc_num]->ht.bgcount[i] = 0;
1586 for (i = 0; i < vc->vc_rows; i++) {
1587 u16 *end = start + vc->vc_cols * 2;
1590 for (ptr = start; ptr < end; ptr++) {
1591 ch = get_attributes(vc, ptr);
1592 bg = (ch & 0x70) >> 4;
1593 speakup_console[vc_num]->ht.bgcount[bg]++;
1595 start += vc->vc_size_row;
1599 for (i = 0; i < 8; i++)
1600 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1605 static int get_highlight_color(struct vc_data *vc)
1608 unsigned int cptr[8];
1609 int vc_num = vc->vc_num;
1611 for (i = 0; i < 8; i++)
1614 for (i = 0; i < 7; i++)
1615 for (j = i + 1; j < 8; j++)
1616 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1617 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1618 swap(cptr[i], cptr[j]);
1620 for (i = 0; i < 8; i++)
1621 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1622 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1627 static int speak_highlight(struct vc_data *vc)
1630 int vc_num = vc->vc_num;
1632 if (count_highlight_color(vc) == 1)
1634 hc = get_highlight_color(vc);
1636 d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1637 if ((d == 1) || (d == -1))
1638 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1642 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1643 speakup_console[vc_num]->ht.highsize[hc]);
1644 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1645 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1646 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1652 static void cursor_done(u_long data)
1654 struct vc_data *vc = vc_cons[cursor_con].d;
1655 unsigned long flags;
1657 del_timer(&cursor_timer);
1658 spin_lock_irqsave(&speakup_info.spinlock, flags);
1659 if (cursor_con != fg_console) {
1665 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1666 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1672 if (cursor_track == read_all_mode) {
1673 handle_cursor_read_all(vc, read_all_key);
1676 if (cursor_track == CT_Highlight) {
1677 if (speak_highlight(vc)) {
1683 if (cursor_track == CT_Window)
1684 speakup_win_say(vc);
1685 else if (is_cursor == 1 || is_cursor == 4)
1686 say_line_from_to(vc, 0, vc->vc_cols, 0);
1692 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1695 /* called by: vt_notifier_call() */
1696 static void speakup_bs(struct vc_data *vc)
1698 unsigned long flags;
1700 if (!speakup_console[vc->vc_num])
1702 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1703 /* Speakup output, discard */
1707 if (spk_shut_up || synth == NULL) {
1708 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1711 if (vc->vc_num == fg_console && spk_keydown) {
1716 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1719 /* called by: vt_notifier_call() */
1720 static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1722 unsigned long flags;
1724 if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1726 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1727 /* Speakup output, discard */
1729 if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1731 if ((is_cursor) || (cursor_track == read_all_mode)) {
1732 if (cursor_track == CT_Highlight)
1733 update_color_buffer(vc, str, len);
1734 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1738 if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1739 vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1740 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1745 spkup_write(str, len);
1746 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1749 static void speakup_con_update(struct vc_data *vc)
1751 unsigned long flags;
1753 if (speakup_console[vc->vc_num] == NULL || spk_parked)
1755 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1756 /* Speakup output, discard */
1759 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1762 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1764 unsigned long flags;
1768 if (synth == NULL || up_flag || spk_killed)
1770 spin_lock_irqsave(&speakup_info.spinlock, flags);
1771 spk_shut_up &= 0xfe;
1776 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1777 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1780 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1781 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1784 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1785 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1786 if (speakup_console[vc->vc_num])
1787 speakup_console[vc->vc_num]->tty_stopped = on_off;
1791 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1795 synth_printf("%s %s\n",
1796 label, spk_msg_get(MSG_STATUS_START + on_off));
1797 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1800 static int inc_dec_var(u_char value)
1802 struct st_var_header *p_header;
1803 struct var_t *var_data;
1807 int var_id = (int)value - VAR_START;
1808 int how = (var_id & 1) ? E_INC : E_DEC;
1810 var_id = var_id / 2 + FIRST_SET_VAR;
1811 p_header = spk_get_var_header(var_id);
1812 if (p_header == NULL)
1814 if (p_header->var_type != VAR_NUM)
1816 var_data = p_header->data;
1817 if (spk_set_num_var(1, p_header, how) != 0)
1819 if (!spk_close_press) {
1820 for (pn = p_header->name; *pn; pn++) {
1827 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1828 var_data->u.n.value);
1829 synth_printf("%s", num_buf);
1833 static void speakup_win_set(struct vc_data *vc)
1837 if (win_start > 1) {
1838 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1841 if (spk_x < win_left || spk_y < win_top) {
1842 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1845 if (win_start && spk_x == win_left && spk_y == win_top) {
1847 win_right = vc->vc_cols - 1;
1849 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1859 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1861 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1862 (int)spk_y + 1, (int)spk_x + 1);
1864 synth_printf("%s\n", info);
1868 static void speakup_win_clear(struct vc_data *vc)
1875 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1878 static void speakup_win_enable(struct vc_data *vc)
1880 if (win_start < 2) {
1881 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1886 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1888 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1891 static void speakup_bits(struct vc_data *vc)
1893 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1895 if (spk_special_handler != NULL || val < 1 || val > 6) {
1896 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1899 pb_edit = &spk_punc_info[val];
1900 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1901 spk_special_handler = edit_bits;
1904 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1906 static u_char goto_buf[8];
1911 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1913 if (type == KT_LATIN && ch == '\n')
1920 ch = goto_buf[--num];
1921 goto_buf[num] = '\0';
1922 spkup_write(&ch, 1);
1925 if (ch < '+' || ch > 'y')
1927 goto_buf[num++] = ch;
1928 goto_buf[num] = '\0';
1929 spkup_write(&ch, 1);
1930 maxlen = (*goto_buf >= '0') ? 3 : 4;
1931 if ((ch == '+' || ch == '-') && num == 1)
1933 if (ch >= '0' && ch <= '9' && num < maxlen)
1935 if (num < maxlen - 1 || num > maxlen)
1937 if (ch < 'x' || ch > 'y') {
1940 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1941 goto_buf[num = 0] = '\0';
1942 spk_special_handler = NULL;
1946 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1949 if (*goto_buf < '0')
1951 else if (goto_pos > 0)
1954 if (goto_pos >= vc->vc_cols)
1955 goto_pos = vc->vc_cols - 1;
1958 if (*goto_buf < '0')
1960 else if (goto_pos > 0)
1963 if (goto_pos >= vc->vc_rows)
1964 goto_pos = vc->vc_rows - 1;
1967 goto_buf[num = 0] = '\0';
1969 spk_special_handler = NULL;
1972 spk_pos -= spk_x * 2;
1974 spk_pos += goto_pos * 2;
1978 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1984 static void speakup_goto(struct vc_data *vc)
1986 if (spk_special_handler != NULL) {
1987 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1990 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1991 spk_special_handler = handle_goto;
1994 static void speakup_help(struct vc_data *vc)
1996 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1999 static void do_nothing(struct vc_data *vc)
2001 return; /* flush done in do_spkup */
2004 static u_char key_speakup, spk_key_locked;
2006 static void speakup_lock(struct vc_data *vc)
2008 if (!spk_key_locked) {
2009 spk_key_locked = 16;
2017 typedef void (*spkup_hand) (struct vc_data *);
2018 static spkup_hand spkup_handler[] = {
2019 /* must be ordered same as defines in speakup.h */
2020 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2021 speakup_cut, speakup_paste, say_first_char, say_last_char,
2022 say_char, say_prev_char, say_next_char,
2023 say_word, say_prev_word, say_next_word,
2024 say_line, say_prev_line, say_next_line,
2025 top_edge, bottom_edge, left_edge, right_edge,
2026 spell_word, spell_word, say_screen,
2027 say_position, say_attributes,
2028 speakup_off, speakup_parked, say_line, /* this is for indent */
2029 say_from_top, say_to_bottom,
2030 say_from_left, say_to_right,
2031 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2032 speakup_bits, speakup_bits, speakup_bits,
2033 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2034 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2037 static void do_spkup(struct vc_data *vc, u_char value)
2039 if (spk_killed && value != SPEECH_KILL)
2043 spk_shut_up &= 0xfe;
2044 this_speakup_key = value;
2045 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2047 (*spkup_handler[value]) (vc);
2049 if (inc_dec_var(value) < 0)
2054 static const char *pad_chars = "0123456789+-*/\015,.?()";
2057 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2060 unsigned long flags;
2063 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2064 u_char shift_info, offset;
2070 spin_lock_irqsave(&speakup_info.spinlock, flags);
2075 && (vt_get_leds(fg_console, VC_NUMLOCK))) {
2080 value = spk_lastkey = pad_chars[value];
2085 if (keycode >= MAX_KEY)
2087 key_info = spk_our_keys[keycode];
2090 /* Check valid read all mode keys */
2091 if ((cursor_track == read_all_mode) && (!up_flag)) {
2105 shift_info = (shift_state & 0x0f) + key_speakup;
2106 offset = spk_shift_table[shift_info];
2108 new_key = key_info[offset];
2111 if (new_key == SPK_KEY) {
2112 if (!spk_key_locked)
2113 key_speakup = (up_flag) ? 0 : 16;
2114 if (up_flag || spk_killed)
2116 spk_shut_up &= 0xfe;
2122 if (last_keycode == keycode &&
2123 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2124 spk_close_press = 1;
2125 offset = spk_shift_table[shift_info + 32];
2127 if (offset && key_info[offset])
2128 new_key = key_info[offset];
2130 last_keycode = keycode;
2131 last_spk_jiffy = jiffies;
2137 if (type == KT_SPKUP && spk_special_handler == NULL) {
2138 do_spkup(vc, new_key);
2139 spk_close_press = 0;
2143 if (up_flag || spk_killed || type == KT_SHIFT)
2145 spk_shut_up &= 0xfe;
2146 kh = (value == KVAL(K_DOWN))
2147 || (value == KVAL(K_UP))
2148 || (value == KVAL(K_LEFT))
2149 || (value == KVAL(K_RIGHT));
2150 if ((cursor_track != read_all_mode) || !kh)
2153 if (spk_special_handler) {
2154 if (type == KT_SPEC && value == 1) {
2157 } else if (type == KT_LETTER)
2159 else if (value == 0x7f)
2160 value = 8; /* make del = backspace */
2161 ret = (*spk_special_handler) (vc, type, value, keycode);
2162 spk_close_press = 0;
2169 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2173 static int keyboard_notifier_call(struct notifier_block *nb,
2174 unsigned long code, void *_param)
2176 struct keyboard_notifier_param *param = _param;
2177 struct vc_data *vc = param->vc;
2178 int up = !param->down;
2179 int ret = NOTIFY_OK;
2180 static int keycode; /* to hold the current keycode */
2182 if (vc->vc_mode == KD_GRAPHICS)
2186 * First, determine whether we are handling a fake keypress on
2187 * the current processor. If we are, then return NOTIFY_OK,
2188 * to pass the keystroke up the chain. This prevents us from
2189 * trying to take the Speakup lock while it is held by the
2190 * processor on which the simulated keystroke was generated.
2191 * Also, the simulated keystrokes should be ignored by Speakup.
2194 if (speakup_fake_key_pressed())
2199 /* speakup requires keycode and keysym currently */
2200 keycode = param->value;
2202 case KBD_UNBOUND_KEYCODE:
2209 if (speakup_key(vc, param->shift, keycode, param->value, up))
2211 else if (KTYP(param->value) == KT_CUR)
2212 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2214 case KBD_POST_KEYSYM:{
2215 unsigned char type = KTYP(param->value) - 0xf0;
2216 unsigned char val = KVAL(param->value);
2220 do_handle_shift(vc, val, up);
2224 do_handle_latin(vc, val, up);
2227 do_handle_cursor(vc, val, up);
2230 do_handle_spec(vc, val, up);
2239 static int vt_notifier_call(struct notifier_block *nb,
2240 unsigned long code, void *_param)
2242 struct vt_notifier_param *param = _param;
2243 struct vc_data *vc = param->vc;
2247 if (vc->vc_mode == KD_TEXT)
2248 speakup_allocate(vc);
2251 speakup_deallocate(vc);
2254 if (param->c == '\b')
2256 else if (param->c < 0x100) {
2259 speakup_con_write(vc, &d, 1);
2263 speakup_con_update(vc);
2269 /* called by: module_exit() */
2270 static void __exit speakup_exit(void)
2274 unregister_keyboard_notifier(&keyboard_notifier_block);
2275 unregister_vt_notifier(&vt_notifier_block);
2276 speakup_unregister_devsynth();
2277 speakup_cancel_paste();
2278 del_timer_sync(&cursor_timer);
2279 kthread_stop(speakup_task);
2280 speakup_task = NULL;
2281 mutex_lock(&spk_mutex);
2283 mutex_unlock(&spk_mutex);
2285 speakup_kobj_exit();
2287 for (i = 0; i < MAX_NR_CONSOLES; i++)
2288 kfree(speakup_console[i]);
2290 speakup_remove_virtual_keyboard();
2292 for (i = 0; i < MAXVARS; i++)
2293 speakup_unregister_var(i);
2295 for (i = 0; i < 256; i++) {
2296 if (spk_characters[i] != spk_default_chars[i])
2297 kfree(spk_characters[i]);
2300 spk_free_user_msgs();
2303 /* call by: module_init() */
2304 static int __init speakup_init(void)
2308 struct st_spk_t *first_console;
2309 struct vc_data *vc = vc_cons[fg_console].d;
2312 /* These first few initializations cannot fail. */
2313 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2314 spk_reset_default_chars();
2315 spk_reset_default_chartab();
2316 spk_strlwr(synth_name);
2317 spk_vars[0].u.n.high = vc->vc_cols;
2318 for (var = spk_vars; var->var_id != MAXVARS; var++)
2319 speakup_register_var(var);
2320 for (var = synth_time_vars;
2321 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2322 speakup_register_var(var);
2323 for (i = 1; spk_punc_info[i].mask != 0; i++)
2324 spk_set_mask_bits(NULL, i, 2);
2326 spk_set_key_info(spk_key_defaults, spk_key_buf);
2328 /* From here on out, initializations can fail. */
2329 err = speakup_add_virtual_keyboard();
2331 goto error_virtkeyboard;
2333 first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2334 if (!first_console) {
2339 speakup_console[vc->vc_num] = first_console;
2342 for (i = 0; i < MAX_NR_CONSOLES; i++)
2344 err = speakup_allocate(vc_cons[i].d);
2346 goto error_kobjects;
2350 spk_shut_up |= 0x01;
2352 err = speakup_kobj_init();
2354 goto error_kobjects;
2356 synth_init(synth_name);
2357 speakup_register_devsynth();
2359 * register_devsynth might fail, but this error is not fatal.
2360 * /dev/synth is an extra feature; the rest of Speakup
2361 * will work fine without it.
2364 err = register_keyboard_notifier(&keyboard_notifier_block);
2366 goto error_kbdnotifier;
2367 err = register_vt_notifier(&vt_notifier_block);
2369 goto error_vtnotifier;
2371 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2373 if (IS_ERR(speakup_task)) {
2374 err = PTR_ERR(speakup_task);
2378 set_user_nice(speakup_task, 10);
2379 wake_up_process(speakup_task);
2381 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2382 pr_info("synth name on entry is: %s\n", synth_name);
2386 unregister_vt_notifier(&vt_notifier_block);
2389 unregister_keyboard_notifier(&keyboard_notifier_block);
2390 del_timer(&cursor_timer);
2393 speakup_unregister_devsynth();
2394 mutex_lock(&spk_mutex);
2396 mutex_unlock(&spk_mutex);
2397 speakup_kobj_exit();
2400 for (i = 0; i < MAX_NR_CONSOLES; i++)
2401 kfree(speakup_console[i]);
2404 speakup_remove_virtual_keyboard();
2407 for (i = 0; i < MAXVARS; i++)
2408 speakup_unregister_var(i);
2410 for (i = 0; i < 256; i++) {
2411 if (spk_characters[i] != spk_default_chars[i])
2412 kfree(spk_characters[i]);
2415 spk_free_user_msgs();
2421 module_init(speakup_init);
2422 module_exit(speakup_exit);