1 // SPDX-License-Identifier: GPL-2.0+
3 * review functions for the speakup screen review package.
4 * originally written by: Kirk Reiser and Andy Berdan.
6 * extensively modified by David Borowski.
8 ** Copyright (C) 1998 Kirk Reiser.
9 * Copyright (C) 2003 David Borowski.
12 #include <linux/kernel.h>
14 #include <linux/tty.h>
15 #include <linux/mm.h> /* __get_free_page() and friends */
16 #include <linux/vt_kern.h>
17 #include <linux/ctype.h>
18 #include <linux/selection.h>
19 #include <linux/unistd.h>
20 #include <linux/jiffies.h>
21 #include <linux/kthread.h>
22 #include <linux/keyboard.h> /* for KT_SHIFT */
23 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
24 #include <linux/input.h>
25 #include <linux/kmod.h>
27 /* speakup_*_selection */
28 #include <linux/module.h>
29 #include <linux/sched.h>
30 #include <linux/slab.h>
31 #include <linux/types.h>
32 #include <linux/consolemap.h>
34 #include <linux/spinlock.h>
35 #include <linux/notifier.h>
37 #include <linux/uaccess.h> /* copy_from|to|user() and others */
42 #define MAX_DELAY msecs_to_jiffies(500)
43 #define MINECHOCHAR SPACE
45 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
46 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
47 MODULE_DESCRIPTION("Speakup console speech");
48 MODULE_LICENSE("GPL");
49 MODULE_VERSION(SPEAKUP_VERSION);
52 module_param_named(synth, synth_name, charp, 0444);
53 module_param_named(quiet, spk_quiet_boot, bool, 0444);
55 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
56 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
58 special_func spk_special_handler;
60 short spk_pitch_shift, synth_flags;
62 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
63 int spk_no_intr, spk_spell_delay;
64 int spk_key_echo, spk_say_word_ctl;
65 int spk_say_ctrl, spk_bell_pos;
67 int spk_punc_level, spk_reading_punc;
68 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
69 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
70 char spk_str_pause[MAXVARLEN + 1] = "\0";
72 const struct st_bits_data spk_punc_info[] = {
74 {"some", "/$%&@", SOME},
75 {"most", "$%&#()=+*/@^<>|\\", MOST},
76 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
77 {"delimiters", "", B_WDLM},
78 {"repeats", "()", CH_RPT},
79 {"extended numeric", "", B_EXNUM},
80 {"symbols", "", B_SYM},
84 static char mark_cut_flag;
86 static u_char *spk_shift_table;
87 u_char *spk_our_keys[MAX_KEY];
88 u_char spk_key_buf[600];
89 const u_char spk_key_defaults[] = {
90 #include "speakupmap.h"
93 /* Speakup Cursor Track Variables */
94 static int cursor_track = 1, prev_cursor_track = 1;
96 /* cursor track modes, must be ordered same as cursor_msgs */
105 #define read_all_mode CT_Max
107 static struct tty_struct *tty;
109 static void spkup_write(const u16 *in_buf, int count);
111 static char *phonetic[] = {
112 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
113 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
115 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
116 "x ray", "yankee", "zulu"
119 /* array of 256 char pointers (one for each character description)
120 * initialized to default_chars and user selectable via
121 * /proc/speakup/characters
123 char *spk_characters[256];
125 char *spk_default_chars[256] = {
126 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
127 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
128 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
129 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
131 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
133 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
136 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
138 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
139 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
140 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
141 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
142 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
145 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
146 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
147 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
148 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
149 /*127*/ "del", "control", "control", "control", "control", "control",
150 "control", "control", "control", "control", "control",
151 /*138*/ "control", "control", "control", "control", "control",
152 "control", "control", "control", "control", "control",
153 "control", "control",
154 /*150*/ "control", "control", "control", "control", "control",
155 "control", "control", "control", "control", "control",
156 /*160*/ "nbsp", "inverted bang",
157 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
158 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
159 /*172*/ "not", "soft hyphen", "registered", "macron",
160 /*176*/ "degrees", "plus or minus", "super two", "super three",
161 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
162 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
163 /*188*/ "one quarter", "one half", "three quarters",
165 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
167 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
169 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
171 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
172 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
174 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
175 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
176 /*230*/ "ae", "c cidella", "e grave", "e acute",
177 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
179 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
181 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
183 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
186 /* array of 256 u_short (one for each character)
187 * initialized to default_chartab and user selectable via
188 * /sys/module/speakup/parameters/chartab
190 u_short spk_chartab[256];
192 static u_short default_chartab[256] = {
193 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
194 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
195 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
196 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
197 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
198 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
199 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
200 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
201 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
202 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
203 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
204 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
205 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
206 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
207 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
208 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
209 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
211 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
213 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
215 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
217 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
219 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
220 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
221 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
222 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
223 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
224 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
225 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
226 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
227 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
228 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
229 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
232 struct task_struct *speakup_task;
233 struct bleep spk_unprocessed_sound;
234 static int spk_keydown;
235 static u16 spk_lastkey;
236 static u_char spk_close_press, keymap_flags;
237 static u_char last_keycode, this_speakup_key;
238 static u_long last_spk_jiffy;
240 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
242 DEFINE_MUTEX(spk_mutex);
244 static int keyboard_notifier_call(struct notifier_block *,
245 unsigned long code, void *param);
247 static struct notifier_block keyboard_notifier_block = {
248 .notifier_call = keyboard_notifier_call,
251 static int vt_notifier_call(struct notifier_block *,
252 unsigned long code, void *param);
254 static struct notifier_block vt_notifier_block = {
255 .notifier_call = vt_notifier_call,
258 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
260 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
261 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
264 static void speakup_date(struct vc_data *vc)
266 spk_x = spk_cx = vc->state.x;
267 spk_y = spk_cy = vc->state.y;
268 spk_pos = spk_cp = vc->vc_pos;
269 spk_old_attr = spk_attr;
270 spk_attr = get_attributes(vc, (u_short *)spk_pos);
273 static void bleep(u_short val)
275 static const short vals[] = {
276 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
279 int time = spk_bleep_time;
281 freq = vals[val % 12];
283 freq *= (1 << (val / 12));
284 spk_unprocessed_sound.freq = freq;
285 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
286 spk_unprocessed_sound.active = 1;
287 /* We can only have 1 active sound at a time. */
290 static void speakup_shut_up(struct vc_data *vc)
301 static void speech_kill(struct vc_data *vc)
303 char val = synth->is_alive(synth);
308 /* re-enables synth, if disabled */
309 if (val == 2 || spk_killed) {
311 spk_shut_up &= ~0x40;
312 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
314 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
319 static void speakup_off(struct vc_data *vc)
321 if (spk_shut_up & 0x80) {
323 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
326 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
331 static void speakup_parked(struct vc_data *vc)
333 if (spk_parked & 0x80) {
335 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
338 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
342 static void speakup_cut(struct vc_data *vc)
344 static const char err_buf[] = "set selection failed";
347 if (!mark_cut_flag) {
349 spk_xs = (u_short)spk_x;
350 spk_ys = (u_short)spk_y;
352 synth_printf("%s\n", spk_msg_get(MSG_MARK));
355 spk_xe = (u_short)spk_x;
356 spk_ye = (u_short)spk_y;
358 synth_printf("%s\n", spk_msg_get(MSG_CUT));
360 ret = speakup_set_selection(tty);
364 break; /* no error */
366 pr_warn("%sEFAULT\n", err_buf);
369 pr_warn("%sEINVAL\n", err_buf);
372 pr_warn("%sENOMEM\n", err_buf);
377 static void speakup_paste(struct vc_data *vc)
381 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
383 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
384 speakup_paste_selection(tty);
388 static void say_attributes(struct vc_data *vc)
390 int fg = spk_attr & 0x0f;
391 int bg = spk_attr >> 4;
394 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
397 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
399 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
402 synth_printf(" %s ", spk_msg_get(MSG_ON));
404 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
415 static void announce_edge(struct vc_data *vc, int msg_id)
419 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
421 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
424 static void speak_char(u16 ch)
427 struct var_t *direct = spk_get_var(DIRECT);
429 if (ch >= 0x100 || (direct && direct->u.n.value)) {
430 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
432 synth_printf("%s", spk_str_caps_start);
435 if (ch < 0x100 && IS_CHAR(ch, B_CAP))
436 synth_printf("%s", spk_str_caps_stop);
440 cp = spk_characters[ch];
442 pr_info("%s: cp == NULL!\n", __func__);
445 if (IS_CHAR(ch, B_CAP)) {
447 synth_printf("%s %s %s",
448 spk_str_caps_start, cp, spk_str_caps_stop);
452 synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
454 synth_printf(" %s ", cp);
459 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
467 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
471 if (w & vc->vc_hi_font_mask) {
472 w &= ~vc->vc_hi_font_mask;
476 ch = inverse_translate(vc, c, 1);
477 *attribs = (w & 0xff00) >> 8;
482 static void say_char(struct vc_data *vc)
486 spk_old_attr = spk_attr;
487 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
488 if (spk_attr != spk_old_attr) {
489 if (spk_attrib_bleep & 1)
491 if (spk_attrib_bleep & 2)
497 static void say_phonetic_char(struct vc_data *vc)
501 spk_old_attr = spk_attr;
502 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
503 if (ch <= 0x7f && isalpha(ch)) {
505 synth_printf("%s\n", phonetic[--ch]);
507 if (ch < 0x100 && IS_CHAR(ch, B_NUM))
508 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
513 static void say_prev_char(struct vc_data *vc)
517 announce_edge(vc, edge_left);
525 static void say_next_char(struct vc_data *vc)
528 if (spk_x == vc->vc_cols - 1) {
529 announce_edge(vc, edge_right);
537 /* get_word - will first check to see if the character under the
538 * reading cursor is a space and if spk_say_word_ctl is true it will
539 * return the word space. If spk_say_word_ctl is not set it will check to
540 * see if there is a word starting on the next position to the right
541 * and return that word if it exists. If it does not exist it will
542 * move left to the beginning of any previous word on the line or the
543 * beginning off the line whichever comes first..
546 static u_long get_word(struct vc_data *vc)
548 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
553 spk_old_attr = spk_attr;
554 ch = get_char(vc, (u_short *)tmp_pos, &temp);
556 /* decided to take out the sayword if on a space (mis-information */
557 if (spk_say_word_ctl && ch == SPACE) {
559 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
561 } else if (tmpx < vc->vc_cols - 2 &&
562 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
563 get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
568 ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
569 if ((ch == SPACE || ch == 0 ||
570 (ch < 0x100 && IS_WDLM(ch))) &&
571 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
577 attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
578 buf[cnt++] = attr_ch;
579 while (tmpx < vc->vc_cols - 1) {
582 ch = get_char(vc, (u_short *)tmp_pos, &temp);
583 if (ch == SPACE || ch == 0 ||
584 (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
593 static void say_word(struct vc_data *vc)
595 u_long cnt = get_word(vc);
596 u_short saved_punc_mask = spk_punc_mask;
600 spk_punc_mask = PUNC;
602 spkup_write(buf, cnt);
603 spk_punc_mask = saved_punc_mask;
606 static void say_prev_word(struct vc_data *vc)
610 u_short edge_said = 0, last_state = 0, state = 0;
616 announce_edge(vc, edge_top);
621 edge_said = edge_quiet;
626 edge_said = edge_top;
629 if (edge_said != edge_quiet)
630 edge_said = edge_left;
634 spk_x = vc->vc_cols - 1;
639 ch = get_char(vc, (u_short *)spk_pos, &temp);
640 if (ch == SPACE || ch == 0)
642 else if (ch < 0x100 && IS_WDLM(ch))
646 if (state < last_state) {
653 if (spk_x == 0 && edge_said == edge_quiet)
654 edge_said = edge_left;
655 if (edge_said > 0 && edge_said < edge_quiet)
656 announce_edge(vc, edge_said);
660 static void say_next_word(struct vc_data *vc)
664 u_short edge_said = 0, last_state = 2, state = 0;
667 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
668 announce_edge(vc, edge_bottom);
672 ch = get_char(vc, (u_short *)spk_pos, &temp);
673 if (ch == SPACE || ch == 0)
675 else if (ch < 0x100 && IS_WDLM(ch))
679 if (state > last_state)
681 if (spk_x >= vc->vc_cols - 1) {
682 if (spk_y == vc->vc_rows - 1) {
683 edge_said = edge_bottom;
689 edge_said = edge_right;
697 announce_edge(vc, edge_said);
701 static void spell_word(struct vc_data *vc)
703 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
706 char *str_cap = spk_str_caps_stop;
707 char *last_cap = spk_str_caps_stop;
708 struct var_t *direct = spk_get_var(DIRECT);
715 synth_printf(" %s ", delay_str[spk_spell_delay]);
716 /* FIXME: Non-latin1 considered as lower case */
717 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
718 str_cap = spk_str_caps_start;
719 if (*spk_str_caps_stop)
721 else /* synth has no pitch */
722 last_cap = spk_str_caps_stop;
724 str_cap = spk_str_caps_stop;
726 if (str_cap != last_cap) {
727 synth_printf("%s", str_cap);
730 if (ch >= 0x100 || (direct && direct->u.n.value)) {
732 } else if (this_speakup_key == SPELL_PHONETIC &&
733 ch <= 0x7f && isalpha(ch)) {
735 cp1 = phonetic[--ch];
736 synth_printf("%s", cp1);
738 cp1 = spk_characters[ch];
740 synth_printf("%s", spk_msg_get(MSG_CTRL));
743 synth_printf("%s", cp1);
747 if (str_cap != spk_str_caps_stop)
748 synth_printf("%s", spk_str_caps_stop);
751 static int get_line(struct vc_data *vc)
753 u_long tmp = spk_pos - (spk_x * 2);
757 spk_old_attr = spk_attr;
758 spk_attr = get_attributes(vc, (u_short *)spk_pos);
759 for (i = 0; i < vc->vc_cols; i++) {
760 buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
763 for (--i; i >= 0; i--)
769 static void say_line(struct vc_data *vc)
771 int i = get_line(vc);
773 u_short saved_punc_mask = spk_punc_mask;
776 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
780 if (this_speakup_key == SAY_LINE_INDENT) {
784 synth_printf("%zd, ", (cp - buf) + 1);
786 spk_punc_mask = spk_punc_masks[spk_reading_punc];
788 spk_punc_mask = saved_punc_mask;
791 static void say_prev_line(struct vc_data *vc)
795 announce_edge(vc, edge_top);
799 spk_pos -= vc->vc_size_row;
803 static void say_next_line(struct vc_data *vc)
806 if (spk_y == vc->vc_rows - 1) {
807 announce_edge(vc, edge_bottom);
811 spk_pos += vc->vc_size_row;
815 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
820 u_short saved_punc_mask = spk_punc_mask;
822 spk_old_attr = spk_attr;
823 spk_attr = get_attributes(vc, (u_short *)from);
825 buf[i++] = get_char(vc, (u_short *)from, &tmp);
827 if (i >= vc->vc_size_row)
830 for (--i; i >= 0; i--)
838 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
841 spk_punc_mask = saved_punc_mask;
845 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
848 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
849 u_long end = start + (to * 2);
852 if (say_from_to(vc, start, end, read_punc) <= 0)
853 if (cursor_track != read_all_mode)
854 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
857 /* Sentence Reading Commands */
859 static int currsentence;
860 static int numsentences[2];
861 static u16 *sentbufend[2];
862 static u16 *sentmarks[2][10];
865 static u16 sentbuf[2][256];
867 static int say_sentence_num(int num, int prev)
870 currsentence = num + 1;
871 if (prev && --bn == -1)
874 if (num > numsentences[bn])
877 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
881 static int get_sentence_buf(struct vc_data *vc, int read_punc)
891 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
892 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
894 numsentences[bn] = 0;
895 sentmarks[bn][0] = &sentbuf[bn][0];
897 spk_old_attr = spk_attr;
898 spk_attr = get_attributes(vc, (u_short *)start);
900 while (start < end) {
901 sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
903 if (sentbuf[bn][i] == SPACE &&
904 sentbuf[bn][i - 1] == '.' &&
905 numsentences[bn] < 9) {
906 /* Sentence Marker */
908 sentmarks[bn][numsentences[bn]] =
914 if (i >= vc->vc_size_row)
918 for (--i; i >= 0; i--)
919 if (sentbuf[bn][i] != SPACE)
925 sentbuf[bn][++i] = SPACE;
926 sentbuf[bn][++i] = '\0';
928 sentbufend[bn] = &sentbuf[bn][i];
929 return numsentences[bn];
932 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
934 u_long start = vc->vc_origin, end;
937 start += from * vc->vc_size_row;
938 if (to > vc->vc_rows)
940 end = vc->vc_origin + (to * vc->vc_size_row);
941 for (from = start; from < end; from = to) {
942 to = from + vc->vc_size_row;
943 say_from_to(vc, from, to, 1);
947 static void say_screen(struct vc_data *vc)
949 say_screen_from_to(vc, 0, vc->vc_rows);
952 static void speakup_win_say(struct vc_data *vc)
954 u_long start, end, from, to;
957 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
960 start = vc->vc_origin + (win_top * vc->vc_size_row);
961 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
962 while (start <= end) {
963 from = start + (win_left * 2);
964 to = start + (win_right * 2);
965 say_from_to(vc, from, to, 1);
966 start += vc->vc_size_row;
970 static void top_edge(struct vc_data *vc)
973 spk_pos = vc->vc_origin + 2 * spk_x;
978 static void bottom_edge(struct vc_data *vc)
981 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
982 spk_y = vc->vc_rows - 1;
986 static void left_edge(struct vc_data *vc)
989 spk_pos -= spk_x * 2;
994 static void right_edge(struct vc_data *vc)
997 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
998 spk_x = vc->vc_cols - 1;
1002 static void say_first_char(struct vc_data *vc)
1004 int i, len = get_line(vc);
1009 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1012 for (i = 0; i < len; i++)
1013 if (buf[i] != SPACE)
1016 spk_pos -= (spk_x - i) * 2;
1018 synth_printf("%d, ", ++i);
1022 static void say_last_char(struct vc_data *vc)
1024 int len = get_line(vc);
1029 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1033 spk_pos -= (spk_x - len) * 2;
1035 synth_printf("%d, ", ++len);
1039 static void say_position(struct vc_data *vc)
1041 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1046 /* Added by brianb */
1047 static void say_char_num(struct vc_data *vc)
1050 u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1052 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1055 /* these are stub functions to keep keyboard.c happy. */
1057 static void say_from_top(struct vc_data *vc)
1059 say_screen_from_to(vc, 0, spk_y);
1062 static void say_to_bottom(struct vc_data *vc)
1064 say_screen_from_to(vc, spk_y, vc->vc_rows);
1067 static void say_from_left(struct vc_data *vc)
1069 say_line_from_to(vc, 0, spk_x, 1);
1072 static void say_to_right(struct vc_data *vc)
1074 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1077 /* end of stub functions. */
1079 static void spkup_write(const u16 *in_buf, int count)
1081 static int rep_count;
1082 static u16 ch = '\0', old_ch = '\0';
1083 static u_short char_type, last_type;
1084 int in_count = count;
1088 if (cursor_track == read_all_mode) {
1089 /* Insert Sentence Index */
1090 if ((in_buf == sentmarks[bn][currsentence]) &&
1091 (currsentence <= numsentences[bn]))
1092 synth_insert_next_index(currsentence++);
1096 char_type = spk_chartab[ch];
1099 if (ch == old_ch && !(char_type & B_NUM)) {
1100 if (++rep_count > 2)
1103 if ((last_type & CH_RPT) && rep_count > 2) {
1105 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1111 if (ch == spk_lastkey) {
1113 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1115 } else if (char_type & B_ALPHA) {
1116 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1117 synth_buffer_add(SPACE);
1119 } else if (char_type & B_NUM) {
1122 } else if (char_type & spk_punc_mask) {
1124 char_type &= ~PUNC; /* for dec nospell processing */
1125 } else if (char_type & SYNTH_OK) {
1126 /* these are usually puncts like . and , which synth
1127 * needs for expression.
1128 * suppress multiple to get rid of long pauses and
1129 * clear repeat count
1131 * repeats on you don't get nothing repeated count
1138 /* send space and record position, if next is num overwrite space */
1140 synth_buffer_add(SPACE);
1145 last_type = char_type;
1148 if (in_count > 2 && rep_count > 2) {
1149 if (last_type & CH_RPT) {
1151 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1159 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1161 static void read_all_doc(struct vc_data *vc);
1162 static void cursor_done(struct timer_list *unused);
1163 static DEFINE_TIMER(cursor_timer, cursor_done);
1165 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1167 unsigned long flags;
1169 if (!synth || up_flag || spk_killed)
1171 spin_lock_irqsave(&speakup_info.spinlock, flags);
1172 if (cursor_track == read_all_mode) {
1175 del_timer(&cursor_timer);
1176 spk_shut_up &= 0xfe;
1181 del_timer(&cursor_timer);
1182 cursor_track = prev_cursor_track;
1183 spk_shut_up &= 0xfe;
1188 spk_shut_up &= 0xfe;
1191 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1192 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1193 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1196 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1198 unsigned long flags;
1200 spin_lock_irqsave(&speakup_info.spinlock, flags);
1204 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1207 if (!synth || spk_killed) {
1208 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1211 spk_shut_up &= 0xfe;
1212 spk_lastkey = value;
1215 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1217 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1220 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1222 int i = 0, states, key_data_len;
1223 const u_char *cp = key_info;
1224 u_char *cp1 = k_buffer;
1225 u_char ch, version, num_keys;
1228 if (version != KEY_MAP_VER) {
1229 pr_debug("version found %d should be %d\n",
1230 version, KEY_MAP_VER);
1234 states = (int)cp[1];
1235 key_data_len = (states + 1) * (num_keys + 1);
1236 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1237 pr_debug("too many key_infos (%d over %u)\n",
1238 key_data_len + SHIFT_TBL_SIZE + 4,
1239 (unsigned int)(sizeof(spk_key_buf)));
1242 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1243 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1244 spk_shift_table = k_buffer;
1245 spk_our_keys[0] = spk_shift_table;
1246 cp1 += SHIFT_TBL_SIZE;
1247 memcpy(cp1, cp, key_data_len + 3);
1248 /* get num_keys, states and data */
1249 cp1 += 2; /* now pointing at shift states */
1250 for (i = 1; i <= states; i++) {
1252 if (ch >= SHIFT_TBL_SIZE) {
1253 pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
1254 ch, SHIFT_TBL_SIZE);
1257 spk_shift_table[ch] = i;
1259 keymap_flags = *cp1++;
1260 while ((ch = *cp1)) {
1261 if (ch >= MAX_KEY) {
1262 pr_debug("(%d), not valid key, (max_allowed = %d)\n",
1266 spk_our_keys[ch] = cp1;
1272 static struct var_t spk_vars[] = {
1273 /* bell must be first to set high limit */
1274 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1275 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1276 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1277 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1278 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1279 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1280 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1281 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1282 {SAY_CONTROL, TOGGLE_0},
1283 {SAY_WORD_CTL, TOGGLE_0},
1284 {NO_INTERRUPT, TOGGLE_0},
1285 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1289 static void toggle_cursoring(struct vc_data *vc)
1291 if (cursor_track == read_all_mode)
1292 cursor_track = prev_cursor_track;
1293 if (++cursor_track >= CT_Max)
1295 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1298 void spk_reset_default_chars(void)
1302 /* First, free any non-default */
1303 for (i = 0; i < 256; i++) {
1304 if (spk_characters[i] &&
1305 (spk_characters[i] != spk_default_chars[i]))
1306 kfree(spk_characters[i]);
1309 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1312 void spk_reset_default_chartab(void)
1314 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1317 static const struct st_bits_data *pb_edit;
1319 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1321 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1323 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1326 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1327 spk_special_handler = NULL;
1330 if (mask < PUNC && !(ch_type & PUNC))
1332 spk_chartab[ch] ^= mask;
1334 synth_printf(" %s\n",
1335 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1336 spk_msg_get(MSG_OFF));
1340 /* Allocation concurrency is protected by the console semaphore */
1341 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1345 vc_num = vc->vc_num;
1346 if (!speakup_console[vc_num]) {
1347 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1349 if (!speakup_console[vc_num])
1352 } else if (!spk_parked) {
1359 static void speakup_deallocate(struct vc_data *vc)
1363 vc_num = vc->vc_num;
1364 kfree(speakup_console[vc_num]);
1365 speakup_console[vc_num] = NULL;
1368 static u_char is_cursor;
1369 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1370 static int cursor_con;
1372 static void reset_highlight_buffers(struct vc_data *);
1374 static int read_all_key;
1376 static int in_keyboard_notifier;
1378 static void start_read_all_timer(struct vc_data *vc, int command);
1392 static void kbd_fakekey2(struct vc_data *vc, int command)
1394 del_timer(&cursor_timer);
1395 speakup_fake_down_arrow();
1396 start_read_all_timer(vc, command);
1399 static void read_all_doc(struct vc_data *vc)
1401 if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1403 if (!synth_supports_indexing())
1405 if (cursor_track != read_all_mode)
1406 prev_cursor_track = cursor_track;
1407 cursor_track = read_all_mode;
1408 spk_reset_index_count(0);
1409 if (get_sentence_buf(vc, 0) == -1) {
1410 del_timer(&cursor_timer);
1411 if (!in_keyboard_notifier)
1412 speakup_fake_down_arrow();
1413 start_read_all_timer(vc, RA_DOWN_ARROW);
1415 say_sentence_num(0, 0);
1416 synth_insert_next_index(0);
1417 start_read_all_timer(vc, RA_TIMER);
1421 static void stop_read_all(struct vc_data *vc)
1423 del_timer(&cursor_timer);
1424 cursor_track = prev_cursor_track;
1425 spk_shut_up &= 0xfe;
1429 static void start_read_all_timer(struct vc_data *vc, int command)
1431 struct var_t *cursor_timeout;
1433 cursor_con = vc->vc_num;
1434 read_all_key = command;
1435 cursor_timeout = spk_get_var(CURSOR_TIME);
1436 mod_timer(&cursor_timer,
1437 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1440 static void handle_cursor_read_all(struct vc_data *vc, int command)
1442 int indcount, sentcount, rv, sn;
1446 /* Get Current Sentence */
1447 spk_get_index_count(&indcount, &sentcount);
1448 /*printk("%d %d ", indcount, sentcount); */
1449 spk_reset_index_count(sentcount + 1);
1450 if (indcount == 1) {
1451 if (!say_sentence_num(sentcount + 1, 0)) {
1452 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1455 synth_insert_next_index(0);
1458 if (!say_sentence_num(sentcount + 1, 1)) {
1460 spk_reset_index_count(sn);
1462 synth_insert_next_index(0);
1464 if (!say_sentence_num(sn, 0)) {
1465 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1468 synth_insert_next_index(0);
1470 start_read_all_timer(vc, RA_TIMER);
1480 if (get_sentence_buf(vc, 0) == -1) {
1481 kbd_fakekey2(vc, RA_DOWN_ARROW);
1483 say_sentence_num(0, 0);
1484 synth_insert_next_index(0);
1485 start_read_all_timer(vc, RA_TIMER);
1488 case RA_FIND_NEXT_SENT:
1489 rv = get_sentence_buf(vc, 0);
1493 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1495 say_sentence_num(1, 0);
1496 synth_insert_next_index(0);
1497 start_read_all_timer(vc, RA_TIMER);
1500 case RA_FIND_PREV_SENT:
1503 spk_get_index_count(&indcount, &sentcount);
1505 kbd_fakekey2(vc, RA_DOWN_ARROW);
1507 start_read_all_timer(vc, RA_TIMER);
1512 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1514 unsigned long flags;
1516 spin_lock_irqsave(&speakup_info.spinlock, flags);
1517 if (cursor_track == read_all_mode) {
1519 if (!synth || up_flag || spk_shut_up) {
1520 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1523 del_timer(&cursor_timer);
1524 spk_shut_up &= 0xfe;
1526 start_read_all_timer(vc, value + 1);
1527 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1530 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1534 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1536 unsigned long flags;
1537 struct var_t *cursor_timeout;
1539 spin_lock_irqsave(&speakup_info.spinlock, flags);
1541 if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1542 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1545 spk_shut_up &= 0xfe;
1548 /* the key press flushes if !no_inter but we want to flush on cursor
1549 * moves regardless of no_inter state
1551 is_cursor = value + 1;
1552 old_cursor_pos = vc->vc_pos;
1553 old_cursor_x = vc->state.x;
1554 old_cursor_y = vc->state.y;
1555 speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1556 cursor_con = vc->vc_num;
1557 if (cursor_track == CT_Highlight)
1558 reset_highlight_buffers(vc);
1559 cursor_timeout = spk_get_var(CURSOR_TIME);
1560 mod_timer(&cursor_timer,
1561 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1562 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1565 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1568 int vc_num = vc->vc_num;
1570 bi = (vc->vc_attr & 0x70) >> 4;
1571 hi = speakup_console[vc_num]->ht.highsize[bi];
1574 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1575 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1576 speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1577 speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1579 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1581 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1583 } else if ((ic[i] == 32) && (hi != 0)) {
1584 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1586 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1593 speakup_console[vc_num]->ht.highsize[bi] = hi;
1596 static void reset_highlight_buffers(struct vc_data *vc)
1599 int vc_num = vc->vc_num;
1601 for (i = 0; i < 8; i++)
1602 speakup_console[vc_num]->ht.highsize[i] = 0;
1605 static int count_highlight_color(struct vc_data *vc)
1609 int vc_num = vc->vc_num;
1611 u16 *start = (u16 *)vc->vc_origin;
1613 for (i = 0; i < 8; i++)
1614 speakup_console[vc_num]->ht.bgcount[i] = 0;
1616 for (i = 0; i < vc->vc_rows; i++) {
1617 u16 *end = start + vc->vc_cols * 2;
1620 for (ptr = start; ptr < end; ptr++) {
1621 ch = get_attributes(vc, ptr);
1622 bg = (ch & 0x70) >> 4;
1623 speakup_console[vc_num]->ht.bgcount[bg]++;
1625 start += vc->vc_size_row;
1629 for (i = 0; i < 8; i++)
1630 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1635 static int get_highlight_color(struct vc_data *vc)
1638 unsigned int cptr[8];
1639 int vc_num = vc->vc_num;
1641 for (i = 0; i < 8; i++)
1644 for (i = 0; i < 7; i++)
1645 for (j = i + 1; j < 8; j++)
1646 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1647 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1648 swap(cptr[i], cptr[j]);
1650 for (i = 0; i < 8; i++)
1651 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1652 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1657 static int speak_highlight(struct vc_data *vc)
1660 int vc_num = vc->vc_num;
1662 if (count_highlight_color(vc) == 1)
1664 hc = get_highlight_color(vc);
1666 d = vc->state.y - speakup_console[vc_num]->ht.cy;
1667 if ((d == 1) || (d == -1))
1668 if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1672 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1673 speakup_console[vc_num]->ht.highsize[hc]);
1674 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1675 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1676 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1682 static void cursor_done(struct timer_list *unused)
1684 struct vc_data *vc = vc_cons[cursor_con].d;
1685 unsigned long flags;
1687 del_timer(&cursor_timer);
1688 spin_lock_irqsave(&speakup_info.spinlock, flags);
1689 if (cursor_con != fg_console) {
1695 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1696 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1702 if (cursor_track == read_all_mode) {
1703 handle_cursor_read_all(vc, read_all_key);
1706 if (cursor_track == CT_Highlight) {
1707 if (speak_highlight(vc)) {
1713 if (cursor_track == CT_Window)
1714 speakup_win_say(vc);
1715 else if (is_cursor == 1 || is_cursor == 4)
1716 say_line_from_to(vc, 0, vc->vc_cols, 0);
1722 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1725 /* called by: vt_notifier_call() */
1726 static void speakup_bs(struct vc_data *vc)
1728 unsigned long flags;
1730 if (!speakup_console[vc->vc_num])
1732 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1733 /* Speakup output, discard */
1737 if (spk_shut_up || !synth) {
1738 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1741 if (vc->vc_num == fg_console && spk_keydown) {
1746 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1749 /* called by: vt_notifier_call() */
1750 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1752 unsigned long flags;
1754 if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1756 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1757 /* Speakup output, discard */
1759 if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1761 if ((is_cursor) || (cursor_track == read_all_mode)) {
1762 if (cursor_track == CT_Highlight)
1763 update_color_buffer(vc, str, len);
1764 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1768 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1769 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1770 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1775 spkup_write(str, len);
1776 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1779 static void speakup_con_update(struct vc_data *vc)
1781 unsigned long flags;
1783 if (!speakup_console[vc->vc_num] || spk_parked)
1785 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1786 /* Speakup output, discard */
1789 if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1790 synth_printf("%s", spk_str_pause);
1793 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1796 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1798 unsigned long flags;
1802 if (!synth || up_flag || spk_killed)
1804 spin_lock_irqsave(&speakup_info.spinlock, flags);
1805 spk_shut_up &= 0xfe;
1810 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1811 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1814 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1815 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1818 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1819 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1820 if (speakup_console[vc->vc_num])
1821 speakup_console[vc->vc_num]->tty_stopped = on_off;
1825 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1829 synth_printf("%s %s\n",
1830 label, spk_msg_get(MSG_STATUS_START + on_off));
1831 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1834 static int inc_dec_var(u_char value)
1836 struct st_var_header *p_header;
1837 struct var_t *var_data;
1841 int var_id = (int)value - VAR_START;
1842 int how = (var_id & 1) ? E_INC : E_DEC;
1844 var_id = var_id / 2 + FIRST_SET_VAR;
1845 p_header = spk_get_var_header(var_id);
1848 if (p_header->var_type != VAR_NUM)
1850 var_data = p_header->data;
1851 if (spk_set_num_var(1, p_header, how) != 0)
1853 if (!spk_close_press) {
1854 for (pn = p_header->name; *pn; pn++) {
1861 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1862 var_data->u.n.value);
1863 synth_printf("%s", num_buf);
1867 static void speakup_win_set(struct vc_data *vc)
1871 if (win_start > 1) {
1872 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1875 if (spk_x < win_left || spk_y < win_top) {
1876 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1879 if (win_start && spk_x == win_left && spk_y == win_top) {
1881 win_right = vc->vc_cols - 1;
1883 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1893 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1895 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1896 (int)spk_y + 1, (int)spk_x + 1);
1898 synth_printf("%s\n", info);
1902 static void speakup_win_clear(struct vc_data *vc)
1909 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1912 static void speakup_win_enable(struct vc_data *vc)
1914 if (win_start < 2) {
1915 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1920 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1922 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1925 static void speakup_bits(struct vc_data *vc)
1927 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1929 if (spk_special_handler || val < 1 || val > 6) {
1930 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1933 pb_edit = &spk_punc_info[val];
1934 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1935 spk_special_handler = edit_bits;
1938 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1940 static u_char goto_buf[8];
1946 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1948 if (type == KT_LATIN && ch == '\n')
1957 wch = goto_buf[--num];
1958 goto_buf[num] = '\0';
1959 spkup_write(&wch, 1);
1962 if (ch < '+' || ch > 'y')
1965 goto_buf[num++] = ch;
1966 goto_buf[num] = '\0';
1967 spkup_write(&wch, 1);
1968 maxlen = (*goto_buf >= '0') ? 3 : 4;
1969 if ((ch == '+' || ch == '-') && num == 1)
1971 if (ch >= '0' && ch <= '9' && num < maxlen)
1973 if (num < maxlen - 1 || num > maxlen)
1975 if (ch < 'x' || ch > 'y') {
1978 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1979 goto_buf[num = 0] = '\0';
1980 spk_special_handler = NULL;
1984 /* Do not replace with kstrtoul: here we need cp to be updated */
1985 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1988 if (*goto_buf < '0')
1990 else if (goto_pos > 0)
1993 if (goto_pos >= vc->vc_cols)
1994 goto_pos = vc->vc_cols - 1;
1997 if (*goto_buf < '0')
1999 else if (goto_pos > 0)
2002 if (goto_pos >= vc->vc_rows)
2003 goto_pos = vc->vc_rows - 1;
2006 goto_buf[num = 0] = '\0';
2008 spk_special_handler = NULL;
2011 spk_pos -= spk_x * 2;
2013 spk_pos += goto_pos * 2;
2017 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2023 static void speakup_goto(struct vc_data *vc)
2025 if (spk_special_handler) {
2026 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2029 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2030 spk_special_handler = handle_goto;
2033 static void speakup_help(struct vc_data *vc)
2035 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2038 static void do_nothing(struct vc_data *vc)
2040 return; /* flush done in do_spkup */
2043 static u_char key_speakup, spk_key_locked;
2045 static void speakup_lock(struct vc_data *vc)
2047 if (!spk_key_locked) {
2048 spk_key_locked = 16;
2056 typedef void (*spkup_hand) (struct vc_data *);
2057 static spkup_hand spkup_handler[] = {
2058 /* must be ordered same as defines in speakup.h */
2059 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2060 speakup_cut, speakup_paste, say_first_char, say_last_char,
2061 say_char, say_prev_char, say_next_char,
2062 say_word, say_prev_word, say_next_word,
2063 say_line, say_prev_line, say_next_line,
2064 top_edge, bottom_edge, left_edge, right_edge,
2065 spell_word, spell_word, say_screen,
2066 say_position, say_attributes,
2067 speakup_off, speakup_parked, say_line, /* this is for indent */
2068 say_from_top, say_to_bottom,
2069 say_from_left, say_to_right,
2070 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2071 speakup_bits, speakup_bits, speakup_bits,
2072 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2073 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2076 static void do_spkup(struct vc_data *vc, u_char value)
2078 if (spk_killed && value != SPEECH_KILL)
2082 spk_shut_up &= 0xfe;
2083 this_speakup_key = value;
2084 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2086 (*spkup_handler[value]) (vc);
2088 if (inc_dec_var(value) < 0)
2093 static const char *pad_chars = "0123456789+-*/\015,.?()";
2096 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2099 unsigned long flags;
2102 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2103 u_char shift_info, offset;
2109 spin_lock_irqsave(&speakup_info.spinlock, flags);
2113 if (type == KT_PAD &&
2114 (vt_get_leds(fg_console, VC_NUMLOCK))) {
2119 value = pad_chars[value];
2120 spk_lastkey = value;
2125 if (keycode >= MAX_KEY)
2127 key_info = spk_our_keys[keycode];
2130 /* Check valid read all mode keys */
2131 if ((cursor_track == read_all_mode) && (!up_flag)) {
2145 shift_info = (shift_state & 0x0f) + key_speakup;
2146 offset = spk_shift_table[shift_info];
2148 new_key = key_info[offset];
2151 if (new_key == SPK_KEY) {
2152 if (!spk_key_locked)
2153 key_speakup = (up_flag) ? 0 : 16;
2154 if (up_flag || spk_killed)
2156 spk_shut_up &= 0xfe;
2162 if (last_keycode == keycode &&
2163 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2164 spk_close_press = 1;
2165 offset = spk_shift_table[shift_info + 32];
2167 if (offset && key_info[offset])
2168 new_key = key_info[offset];
2170 last_keycode = keycode;
2171 last_spk_jiffy = jiffies;
2177 if (type == KT_SPKUP && !spk_special_handler) {
2178 do_spkup(vc, new_key);
2179 spk_close_press = 0;
2183 if (up_flag || spk_killed || type == KT_SHIFT)
2185 spk_shut_up &= 0xfe;
2186 kh = (value == KVAL(K_DOWN)) ||
2187 (value == KVAL(K_UP)) ||
2188 (value == KVAL(K_LEFT)) ||
2189 (value == KVAL(K_RIGHT));
2190 if ((cursor_track != read_all_mode) || !kh)
2193 if (spk_special_handler) {
2194 if (type == KT_SPEC && value == 1) {
2197 } else if (type == KT_LETTER) {
2199 } else if (value == 0x7f) {
2200 value = 8; /* make del = backspace */
2202 ret = (*spk_special_handler) (vc, type, value, keycode);
2203 spk_close_press = 0;
2210 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2214 static int keyboard_notifier_call(struct notifier_block *nb,
2215 unsigned long code, void *_param)
2217 struct keyboard_notifier_param *param = _param;
2218 struct vc_data *vc = param->vc;
2219 int up = !param->down;
2220 int ret = NOTIFY_OK;
2221 static int keycode; /* to hold the current keycode */
2223 in_keyboard_notifier = 1;
2225 if (vc->vc_mode == KD_GRAPHICS)
2229 * First, determine whether we are handling a fake keypress on
2230 * the current processor. If we are, then return NOTIFY_OK,
2231 * to pass the keystroke up the chain. This prevents us from
2232 * trying to take the Speakup lock while it is held by the
2233 * processor on which the simulated keystroke was generated.
2234 * Also, the simulated keystrokes should be ignored by Speakup.
2237 if (speakup_fake_key_pressed())
2242 /* speakup requires keycode and keysym currently */
2243 keycode = param->value;
2245 case KBD_UNBOUND_KEYCODE:
2252 if (speakup_key(vc, param->shift, keycode, param->value, up))
2254 else if (KTYP(param->value) == KT_CUR)
2255 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2257 case KBD_POST_KEYSYM:{
2258 unsigned char type = KTYP(param->value) - 0xf0;
2259 unsigned char val = KVAL(param->value);
2263 do_handle_shift(vc, val, up);
2267 do_handle_latin(vc, val, up);
2270 do_handle_cursor(vc, val, up);
2273 do_handle_spec(vc, val, up);
2280 in_keyboard_notifier = 0;
2284 static int vt_notifier_call(struct notifier_block *nb,
2285 unsigned long code, void *_param)
2287 struct vt_notifier_param *param = _param;
2288 struct vc_data *vc = param->vc;
2292 if (vc->vc_mode == KD_TEXT)
2293 speakup_allocate(vc, GFP_ATOMIC);
2296 speakup_deallocate(vc);
2299 if (param->c == '\b') {
2304 speakup_con_write(vc, &d, 1);
2308 speakup_con_update(vc);
2314 /* called by: module_exit() */
2315 static void __exit speakup_exit(void)
2319 unregister_keyboard_notifier(&keyboard_notifier_block);
2320 unregister_vt_notifier(&vt_notifier_block);
2321 speakup_unregister_devsynth();
2322 speakup_cancel_selection();
2323 speakup_cancel_paste();
2324 del_timer_sync(&cursor_timer);
2325 kthread_stop(speakup_task);
2326 speakup_task = NULL;
2327 mutex_lock(&spk_mutex);
2329 mutex_unlock(&spk_mutex);
2330 spk_ttyio_unregister_ldisc();
2332 speakup_kobj_exit();
2334 for (i = 0; i < MAX_NR_CONSOLES; i++)
2335 kfree(speakup_console[i]);
2337 speakup_remove_virtual_keyboard();
2339 for (i = 0; i < MAXVARS; i++)
2340 speakup_unregister_var(i);
2342 for (i = 0; i < 256; i++) {
2343 if (spk_characters[i] != spk_default_chars[i])
2344 kfree(spk_characters[i]);
2347 spk_free_user_msgs();
2350 /* call by: module_init() */
2351 static int __init speakup_init(void)
2355 struct vc_data *vc = vc_cons[fg_console].d;
2358 /* These first few initializations cannot fail. */
2359 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2360 spk_reset_default_chars();
2361 spk_reset_default_chartab();
2362 spk_strlwr(synth_name);
2363 spk_vars[0].u.n.high = vc->vc_cols;
2364 for (var = spk_vars; var->var_id != MAXVARS; var++)
2365 speakup_register_var(var);
2366 for (var = synth_time_vars;
2367 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2368 speakup_register_var(var);
2369 for (i = 1; spk_punc_info[i].mask != 0; i++)
2370 spk_set_mask_bits(NULL, i, 2);
2372 spk_set_key_info(spk_key_defaults, spk_key_buf);
2374 /* From here on out, initializations can fail. */
2375 err = speakup_add_virtual_keyboard();
2377 goto error_virtkeyboard;
2379 for (i = 0; i < MAX_NR_CONSOLES; i++)
2381 err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2383 goto error_kobjects;
2387 spk_shut_up |= 0x01;
2389 err = speakup_kobj_init();
2391 goto error_kobjects;
2393 spk_ttyio_register_ldisc();
2394 synth_init(synth_name);
2395 speakup_register_devsynth();
2397 * register_devsynth might fail, but this error is not fatal.
2398 * /dev/synth is an extra feature; the rest of Speakup
2399 * will work fine without it.
2402 err = register_keyboard_notifier(&keyboard_notifier_block);
2404 goto error_kbdnotifier;
2405 err = register_vt_notifier(&vt_notifier_block);
2407 goto error_vtnotifier;
2409 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2411 if (IS_ERR(speakup_task)) {
2412 err = PTR_ERR(speakup_task);
2416 set_user_nice(speakup_task, 10);
2417 wake_up_process(speakup_task);
2419 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2420 pr_info("synth name on entry is: %s\n", synth_name);
2424 unregister_vt_notifier(&vt_notifier_block);
2427 unregister_keyboard_notifier(&keyboard_notifier_block);
2428 del_timer(&cursor_timer);
2431 speakup_unregister_devsynth();
2432 mutex_lock(&spk_mutex);
2434 mutex_unlock(&spk_mutex);
2435 speakup_kobj_exit();
2438 for (i = 0; i < MAX_NR_CONSOLES; i++)
2439 kfree(speakup_console[i]);
2441 speakup_remove_virtual_keyboard();
2444 for (i = 0; i < MAXVARS; i++)
2445 speakup_unregister_var(i);
2447 for (i = 0; i < 256; i++) {
2448 if (spk_characters[i] != spk_default_chars[i])
2449 kfree(spk_characters[i]);
2452 spk_free_user_msgs();
2458 module_init(speakup_init);
2459 module_exit(speakup_exit);