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 /* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */
100 read_all_mode = CT_Max,
103 /* Speakup Cursor Track Variables */
104 static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
106 static struct tty_struct *tty;
108 static void spkup_write(const u16 *in_buf, int count);
110 static char *phonetic[] = {
111 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
112 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
114 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
115 "x ray", "yankee", "zulu"
118 /* array of 256 char pointers (one for each character description)
119 * initialized to default_chars and user selectable via
120 * /proc/speakup/characters
122 char *spk_characters[256];
124 char *spk_default_chars[256] = {
125 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
126 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
127 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
128 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
130 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
132 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
135 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
137 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
138 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
139 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
140 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
141 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
144 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
145 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
146 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
147 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
148 /*127*/ "del", "control", "control", "control", "control", "control",
149 "control", "control", "control", "control", "control",
150 /*138*/ "control", "control", "control", "control", "control",
151 "control", "control", "control", "control", "control",
152 "control", "control",
153 /*150*/ "control", "control", "control", "control", "control",
154 "control", "control", "control", "control", "control",
155 /*160*/ "nbsp", "inverted bang",
156 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
157 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
158 /*172*/ "not", "soft hyphen", "registered", "macron",
159 /*176*/ "degrees", "plus or minus", "super two", "super three",
160 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
161 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
162 /*188*/ "one quarter", "one half", "three quarters",
164 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
166 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
168 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
170 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
171 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
173 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
174 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
175 /*230*/ "ae", "c cidella", "e grave", "e acute",
176 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
178 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
180 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
182 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
185 /* array of 256 u_short (one for each character)
186 * initialized to default_chartab and user selectable via
187 * /sys/module/speakup/parameters/chartab
189 u_short spk_chartab[256];
191 static u_short default_chartab[256] = {
192 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
193 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
194 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
195 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
196 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
197 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
198 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
199 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
200 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
201 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
202 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
203 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
204 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
205 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
206 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
207 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
208 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
210 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
212 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
214 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
216 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
218 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
219 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
220 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
221 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
222 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
223 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
224 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
225 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
226 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
227 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
228 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
231 struct task_struct *speakup_task;
232 struct bleep spk_unprocessed_sound;
233 static int spk_keydown;
234 static u16 spk_lastkey;
235 static u_char spk_close_press, keymap_flags;
236 static u_char last_keycode, this_speakup_key;
237 static u_long last_spk_jiffy;
239 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
241 DEFINE_MUTEX(spk_mutex);
243 static int keyboard_notifier_call(struct notifier_block *,
244 unsigned long code, void *param);
246 static struct notifier_block keyboard_notifier_block = {
247 .notifier_call = keyboard_notifier_call,
250 static int vt_notifier_call(struct notifier_block *,
251 unsigned long code, void *param);
253 static struct notifier_block vt_notifier_block = {
254 .notifier_call = vt_notifier_call,
257 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
259 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
260 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
263 static void speakup_date(struct vc_data *vc)
265 spk_x = spk_cx = vc->state.x;
266 spk_y = spk_cy = vc->state.y;
267 spk_pos = spk_cp = vc->vc_pos;
268 spk_old_attr = spk_attr;
269 spk_attr = get_attributes(vc, (u_short *)spk_pos);
272 static void bleep(u_short val)
274 static const short vals[] = {
275 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
278 int time = spk_bleep_time;
280 freq = vals[val % 12];
282 freq *= (1 << (val / 12));
283 spk_unprocessed_sound.freq = freq;
284 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
285 spk_unprocessed_sound.active = 1;
286 /* We can only have 1 active sound at a time. */
289 static void speakup_shut_up(struct vc_data *vc)
300 static void speech_kill(struct vc_data *vc)
302 char val = synth->is_alive(synth);
307 /* re-enables synth, if disabled */
308 if (val == 2 || spk_killed) {
310 spk_shut_up &= ~0x40;
311 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
313 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
318 static void speakup_off(struct vc_data *vc)
320 if (spk_shut_up & 0x80) {
322 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
325 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
330 static void speakup_parked(struct vc_data *vc)
332 if (spk_parked & 0x80) {
334 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
337 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
341 static void speakup_cut(struct vc_data *vc)
343 static const char err_buf[] = "set selection failed";
346 if (!mark_cut_flag) {
348 spk_xs = (u_short)spk_x;
349 spk_ys = (u_short)spk_y;
351 synth_printf("%s\n", spk_msg_get(MSG_MARK));
354 spk_xe = (u_short)spk_x;
355 spk_ye = (u_short)spk_y;
357 synth_printf("%s\n", spk_msg_get(MSG_CUT));
359 ret = speakup_set_selection(tty);
363 break; /* no error */
365 pr_warn("%sEFAULT\n", err_buf);
368 pr_warn("%sEINVAL\n", err_buf);
371 pr_warn("%sENOMEM\n", err_buf);
376 static void speakup_paste(struct vc_data *vc)
380 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
382 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
383 speakup_paste_selection(tty);
387 static void say_attributes(struct vc_data *vc)
389 int fg = spk_attr & 0x0f;
390 int bg = spk_attr >> 4;
392 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
394 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
397 synth_printf(" %s ", spk_msg_get(MSG_ON));
399 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
402 /* must be ordered same as edge_msgs in enum msg_index_t */
412 static void announce_edge(struct vc_data *vc, enum edge msg_id)
416 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
418 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
421 static void speak_char(u16 ch)
424 struct var_t *direct = spk_get_var(DIRECT);
426 if (ch >= 0x100 || (direct && direct->u.n.value)) {
427 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
429 synth_printf("%s", spk_str_caps_start);
432 if (ch < 0x100 && IS_CHAR(ch, B_CAP))
433 synth_printf("%s", spk_str_caps_stop);
437 cp = spk_characters[ch];
439 pr_info("%s: cp == NULL!\n", __func__);
442 if (IS_CHAR(ch, B_CAP)) {
444 synth_printf("%s %s %s",
445 spk_str_caps_start, cp, spk_str_caps_stop);
449 synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
451 synth_printf(" %s ", cp);
456 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
464 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
468 if (w & vc->vc_hi_font_mask) {
469 w &= ~vc->vc_hi_font_mask;
473 ch = inverse_translate(vc, c, 1);
474 *attribs = (w & 0xff00) >> 8;
479 static void say_char(struct vc_data *vc)
483 spk_old_attr = spk_attr;
484 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
485 if (spk_attr != spk_old_attr) {
486 if (spk_attrib_bleep & 1)
488 if (spk_attrib_bleep & 2)
494 static void say_phonetic_char(struct vc_data *vc)
498 spk_old_attr = spk_attr;
499 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
500 if (ch <= 0x7f && isalpha(ch)) {
502 synth_printf("%s\n", phonetic[--ch]);
504 if (ch < 0x100 && IS_CHAR(ch, B_NUM))
505 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
510 static void say_prev_char(struct vc_data *vc)
514 announce_edge(vc, edge_left);
522 static void say_next_char(struct vc_data *vc)
525 if (spk_x == vc->vc_cols - 1) {
526 announce_edge(vc, edge_right);
534 /* get_word - will first check to see if the character under the
535 * reading cursor is a space and if spk_say_word_ctl is true it will
536 * return the word space. If spk_say_word_ctl is not set it will check to
537 * see if there is a word starting on the next position to the right
538 * and return that word if it exists. If it does not exist it will
539 * move left to the beginning of any previous word on the line or the
540 * beginning off the line whichever comes first..
543 static u_long get_word(struct vc_data *vc)
545 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
550 spk_old_attr = spk_attr;
551 ch = get_char(vc, (u_short *)tmp_pos, &temp);
553 /* decided to take out the sayword if on a space (mis-information */
554 if (spk_say_word_ctl && ch == SPACE) {
556 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
558 } else if (tmpx < vc->vc_cols - 2 &&
559 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
560 get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
565 ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
566 if ((ch == SPACE || ch == 0 ||
567 (ch < 0x100 && IS_WDLM(ch))) &&
568 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
574 attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
575 buf[cnt++] = attr_ch;
576 while (tmpx < vc->vc_cols - 1) {
579 ch = get_char(vc, (u_short *)tmp_pos, &temp);
580 if (ch == SPACE || ch == 0 ||
581 (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
590 static void say_word(struct vc_data *vc)
592 u_long cnt = get_word(vc);
593 u_short saved_punc_mask = spk_punc_mask;
597 spk_punc_mask = PUNC;
599 spkup_write(buf, cnt);
600 spk_punc_mask = saved_punc_mask;
603 static void say_prev_word(struct vc_data *vc)
607 enum edge edge_said = edge_none;
608 u_short last_state = 0, state = 0;
614 announce_edge(vc, edge_top);
619 edge_said = edge_quiet;
624 edge_said = edge_top;
627 if (edge_said != edge_quiet)
628 edge_said = edge_left;
632 spk_x = vc->vc_cols - 1;
637 ch = get_char(vc, (u_short *)spk_pos, &temp);
638 if (ch == SPACE || ch == 0)
640 else if (ch < 0x100 && IS_WDLM(ch))
644 if (state < last_state) {
651 if (spk_x == 0 && edge_said == edge_quiet)
652 edge_said = edge_left;
653 if (edge_said > edge_none && edge_said < edge_quiet)
654 announce_edge(vc, edge_said);
658 static void say_next_word(struct vc_data *vc)
662 enum edge edge_said = edge_none;
663 u_short last_state = 2, state = 0;
666 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
667 announce_edge(vc, edge_bottom);
671 ch = get_char(vc, (u_short *)spk_pos, &temp);
672 if (ch == SPACE || ch == 0)
674 else if (ch < 0x100 && IS_WDLM(ch))
678 if (state > last_state)
680 if (spk_x >= vc->vc_cols - 1) {
681 if (spk_y == vc->vc_rows - 1) {
682 edge_said = edge_bottom;
688 edge_said = edge_right;
695 if (edge_said > edge_none)
696 announce_edge(vc, edge_said);
700 static void spell_word(struct vc_data *vc)
702 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
705 char *str_cap = spk_str_caps_stop;
706 char *last_cap = spk_str_caps_stop;
707 struct var_t *direct = spk_get_var(DIRECT);
714 synth_printf(" %s ", delay_str[spk_spell_delay]);
715 /* FIXME: Non-latin1 considered as lower case */
716 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
717 str_cap = spk_str_caps_start;
718 if (*spk_str_caps_stop)
720 else /* synth has no pitch */
721 last_cap = spk_str_caps_stop;
723 str_cap = spk_str_caps_stop;
725 if (str_cap != last_cap) {
726 synth_printf("%s", str_cap);
729 if (ch >= 0x100 || (direct && direct->u.n.value)) {
731 } else if (this_speakup_key == SPELL_PHONETIC &&
732 ch <= 0x7f && isalpha(ch)) {
734 cp1 = phonetic[--ch];
735 synth_printf("%s", cp1);
737 cp1 = spk_characters[ch];
739 synth_printf("%s", spk_msg_get(MSG_CTRL));
742 synth_printf("%s", cp1);
746 if (str_cap != spk_str_caps_stop)
747 synth_printf("%s", spk_str_caps_stop);
750 static int get_line(struct vc_data *vc)
752 u_long tmp = spk_pos - (spk_x * 2);
756 spk_old_attr = spk_attr;
757 spk_attr = get_attributes(vc, (u_short *)spk_pos);
758 for (i = 0; i < vc->vc_cols; i++) {
759 buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
762 for (--i; i >= 0; i--)
768 static void say_line(struct vc_data *vc)
770 int i = get_line(vc);
772 u_short saved_punc_mask = spk_punc_mask;
775 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
779 if (this_speakup_key == SAY_LINE_INDENT) {
783 synth_printf("%zd, ", (cp - buf) + 1);
785 spk_punc_mask = spk_punc_masks[spk_reading_punc];
787 spk_punc_mask = saved_punc_mask;
790 static void say_prev_line(struct vc_data *vc)
794 announce_edge(vc, edge_top);
798 spk_pos -= vc->vc_size_row;
802 static void say_next_line(struct vc_data *vc)
805 if (spk_y == vc->vc_rows - 1) {
806 announce_edge(vc, edge_bottom);
810 spk_pos += vc->vc_size_row;
814 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
819 u_short saved_punc_mask = spk_punc_mask;
821 spk_old_attr = spk_attr;
822 spk_attr = get_attributes(vc, (u_short *)from);
824 buf[i++] = get_char(vc, (u_short *)from, &tmp);
826 if (i >= vc->vc_size_row)
829 for (--i; i >= 0; i--)
837 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
840 spk_punc_mask = saved_punc_mask;
844 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
847 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
848 u_long end = start + (to * 2);
851 if (say_from_to(vc, start, end, read_punc) <= 0)
852 if (cursor_track != read_all_mode)
853 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
856 /* Sentence Reading Commands */
858 static int currsentence;
859 static int numsentences[2];
860 static u16 *sentbufend[2];
861 static u16 *sentmarks[2][10];
864 static u16 sentbuf[2][256];
866 static int say_sentence_num(int num, int prev)
869 currsentence = num + 1;
870 if (prev && --bn == -1)
873 if (num > numsentences[bn])
876 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
880 static int get_sentence_buf(struct vc_data *vc, int read_punc)
890 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
891 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
893 numsentences[bn] = 0;
894 sentmarks[bn][0] = &sentbuf[bn][0];
896 spk_old_attr = spk_attr;
897 spk_attr = get_attributes(vc, (u_short *)start);
899 while (start < end) {
900 sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
902 if (sentbuf[bn][i] == SPACE &&
903 sentbuf[bn][i - 1] == '.' &&
904 numsentences[bn] < 9) {
905 /* Sentence Marker */
907 sentmarks[bn][numsentences[bn]] =
913 if (i >= vc->vc_size_row)
917 for (--i; i >= 0; i--)
918 if (sentbuf[bn][i] != SPACE)
924 sentbuf[bn][++i] = SPACE;
925 sentbuf[bn][++i] = '\0';
927 sentbufend[bn] = &sentbuf[bn][i];
928 return numsentences[bn];
931 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
933 u_long start = vc->vc_origin, end;
936 start += from * vc->vc_size_row;
937 if (to > vc->vc_rows)
939 end = vc->vc_origin + (to * vc->vc_size_row);
940 for (from = start; from < end; from = to) {
941 to = from + vc->vc_size_row;
942 say_from_to(vc, from, to, 1);
946 static void say_screen(struct vc_data *vc)
948 say_screen_from_to(vc, 0, vc->vc_rows);
951 static void speakup_win_say(struct vc_data *vc)
953 u_long start, end, from, to;
956 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
959 start = vc->vc_origin + (win_top * vc->vc_size_row);
960 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
961 while (start <= end) {
962 from = start + (win_left * 2);
963 to = start + (win_right * 2);
964 say_from_to(vc, from, to, 1);
965 start += vc->vc_size_row;
969 static void top_edge(struct vc_data *vc)
972 spk_pos = vc->vc_origin + 2 * spk_x;
977 static void bottom_edge(struct vc_data *vc)
980 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
981 spk_y = vc->vc_rows - 1;
985 static void left_edge(struct vc_data *vc)
988 spk_pos -= spk_x * 2;
993 static void right_edge(struct vc_data *vc)
996 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
997 spk_x = vc->vc_cols - 1;
1001 static void say_first_char(struct vc_data *vc)
1003 int i, len = get_line(vc);
1008 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1011 for (i = 0; i < len; i++)
1012 if (buf[i] != SPACE)
1015 spk_pos -= (spk_x - i) * 2;
1017 synth_printf("%d, ", ++i);
1021 static void say_last_char(struct vc_data *vc)
1023 int len = get_line(vc);
1028 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1032 spk_pos -= (spk_x - len) * 2;
1034 synth_printf("%d, ", ++len);
1038 static void say_position(struct vc_data *vc)
1040 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1045 /* Added by brianb */
1046 static void say_char_num(struct vc_data *vc)
1049 u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1051 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1054 /* these are stub functions to keep keyboard.c happy. */
1056 static void say_from_top(struct vc_data *vc)
1058 say_screen_from_to(vc, 0, spk_y);
1061 static void say_to_bottom(struct vc_data *vc)
1063 say_screen_from_to(vc, spk_y, vc->vc_rows);
1066 static void say_from_left(struct vc_data *vc)
1068 say_line_from_to(vc, 0, spk_x, 1);
1071 static void say_to_right(struct vc_data *vc)
1073 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1076 /* end of stub functions. */
1078 static void spkup_write(const u16 *in_buf, int count)
1080 static int rep_count;
1081 static u16 ch = '\0', old_ch = '\0';
1082 static u_short char_type, last_type;
1083 int in_count = count;
1087 if (cursor_track == read_all_mode) {
1088 /* Insert Sentence Index */
1089 if ((in_buf == sentmarks[bn][currsentence]) &&
1090 (currsentence <= numsentences[bn]))
1091 synth_insert_next_index(currsentence++);
1095 char_type = spk_chartab[ch];
1098 if (ch == old_ch && !(char_type & B_NUM)) {
1099 if (++rep_count > 2)
1102 if ((last_type & CH_RPT) && rep_count > 2) {
1104 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1110 if (ch == spk_lastkey) {
1112 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1114 } else if (char_type & B_ALPHA) {
1115 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1116 synth_buffer_add(SPACE);
1118 } else if (char_type & B_NUM) {
1121 } else if (char_type & spk_punc_mask) {
1123 char_type &= ~PUNC; /* for dec nospell processing */
1124 } else if (char_type & SYNTH_OK) {
1125 /* these are usually puncts like . and , which synth
1126 * needs for expression.
1127 * suppress multiple to get rid of long pauses and
1128 * clear repeat count
1130 * repeats on you don't get nothing repeated count
1137 /* send space and record position, if next is num overwrite space */
1139 synth_buffer_add(SPACE);
1144 last_type = char_type;
1147 if (in_count > 2 && rep_count > 2) {
1148 if (last_type & CH_RPT) {
1150 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1158 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1160 static void read_all_doc(struct vc_data *vc);
1161 static void cursor_done(struct timer_list *unused);
1162 static DEFINE_TIMER(cursor_timer, cursor_done);
1164 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1166 unsigned long flags;
1168 if (!synth || up_flag || spk_killed)
1170 spin_lock_irqsave(&speakup_info.spinlock, flags);
1171 if (cursor_track == read_all_mode) {
1174 del_timer(&cursor_timer);
1175 spk_shut_up &= 0xfe;
1180 del_timer(&cursor_timer);
1181 cursor_track = prev_cursor_track;
1182 spk_shut_up &= 0xfe;
1187 spk_shut_up &= 0xfe;
1190 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1191 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1192 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1195 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1197 unsigned long flags;
1199 spin_lock_irqsave(&speakup_info.spinlock, flags);
1203 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1206 if (!synth || spk_killed) {
1207 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1210 spk_shut_up &= 0xfe;
1211 spk_lastkey = value;
1214 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1216 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1219 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1221 int i = 0, states, key_data_len;
1222 const u_char *cp = key_info;
1223 u_char *cp1 = k_buffer;
1224 u_char ch, version, num_keys;
1227 if (version != KEY_MAP_VER) {
1228 pr_debug("version found %d should be %d\n",
1229 version, KEY_MAP_VER);
1233 states = (int)cp[1];
1234 key_data_len = (states + 1) * (num_keys + 1);
1235 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1236 pr_debug("too many key_infos (%d over %u)\n",
1237 key_data_len + SHIFT_TBL_SIZE + 4,
1238 (unsigned int)(sizeof(spk_key_buf)));
1241 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1242 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1243 spk_shift_table = k_buffer;
1244 spk_our_keys[0] = spk_shift_table;
1245 cp1 += SHIFT_TBL_SIZE;
1246 memcpy(cp1, cp, key_data_len + 3);
1247 /* get num_keys, states and data */
1248 cp1 += 2; /* now pointing at shift states */
1249 for (i = 1; i <= states; i++) {
1251 if (ch >= SHIFT_TBL_SIZE) {
1252 pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
1253 ch, SHIFT_TBL_SIZE);
1256 spk_shift_table[ch] = i;
1258 keymap_flags = *cp1++;
1259 while ((ch = *cp1)) {
1260 if (ch >= MAX_KEY) {
1261 pr_debug("(%d), not valid key, (max_allowed = %d)\n",
1265 spk_our_keys[ch] = cp1;
1271 static struct var_t spk_vars[] = {
1272 /* bell must be first to set high limit */
1273 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1274 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1275 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1276 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1277 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1278 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1279 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1280 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1281 {SAY_CONTROL, TOGGLE_0},
1282 {SAY_WORD_CTL, TOGGLE_0},
1283 {NO_INTERRUPT, TOGGLE_0},
1284 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1288 static void toggle_cursoring(struct vc_data *vc)
1290 if (cursor_track == read_all_mode)
1291 cursor_track = prev_cursor_track;
1292 if (++cursor_track >= CT_Max)
1294 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1297 void spk_reset_default_chars(void)
1301 /* First, free any non-default */
1302 for (i = 0; i < 256; i++) {
1303 if (spk_characters[i] &&
1304 (spk_characters[i] != spk_default_chars[i]))
1305 kfree(spk_characters[i]);
1308 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1311 void spk_reset_default_chartab(void)
1313 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1316 static const struct st_bits_data *pb_edit;
1318 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1320 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1322 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1325 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1326 spk_special_handler = NULL;
1329 if (mask < PUNC && !(ch_type & PUNC))
1331 spk_chartab[ch] ^= mask;
1333 synth_printf(" %s\n",
1334 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1335 spk_msg_get(MSG_OFF));
1339 /* Allocation concurrency is protected by the console semaphore */
1340 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1344 vc_num = vc->vc_num;
1345 if (!speakup_console[vc_num]) {
1346 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1348 if (!speakup_console[vc_num])
1351 } else if (!spk_parked) {
1358 static void speakup_deallocate(struct vc_data *vc)
1362 vc_num = vc->vc_num;
1363 kfree(speakup_console[vc_num]);
1364 speakup_console[vc_num] = NULL;
1367 enum read_all_command {
1368 RA_NEXT_SENT = KVAL(K_DOWN)+1,
1369 RA_PREV_LINE = KVAL(K_LEFT)+1,
1370 RA_NEXT_LINE = KVAL(K_RIGHT)+1,
1371 RA_PREV_SENT = KVAL(K_UP)+1,
1378 static u_char is_cursor;
1379 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1380 static int cursor_con;
1382 static void reset_highlight_buffers(struct vc_data *);
1384 static enum read_all_command read_all_key;
1386 static int in_keyboard_notifier;
1388 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1390 static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
1392 del_timer(&cursor_timer);
1393 speakup_fake_down_arrow();
1394 start_read_all_timer(vc, command);
1397 static void read_all_doc(struct vc_data *vc)
1399 if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1401 if (!synth_supports_indexing())
1403 if (cursor_track != read_all_mode)
1404 prev_cursor_track = cursor_track;
1405 cursor_track = read_all_mode;
1406 spk_reset_index_count(0);
1407 if (get_sentence_buf(vc, 0) == -1) {
1408 del_timer(&cursor_timer);
1409 if (!in_keyboard_notifier)
1410 speakup_fake_down_arrow();
1411 start_read_all_timer(vc, RA_DOWN_ARROW);
1413 say_sentence_num(0, 0);
1414 synth_insert_next_index(0);
1415 start_read_all_timer(vc, RA_TIMER);
1419 static void stop_read_all(struct vc_data *vc)
1421 del_timer(&cursor_timer);
1422 cursor_track = prev_cursor_track;
1423 spk_shut_up &= 0xfe;
1427 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
1429 struct var_t *cursor_timeout;
1431 cursor_con = vc->vc_num;
1432 read_all_key = command;
1433 cursor_timeout = spk_get_var(CURSOR_TIME);
1434 mod_timer(&cursor_timer,
1435 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1438 static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
1440 int indcount, sentcount, rv, sn;
1444 /* Get Current Sentence */
1445 spk_get_index_count(&indcount, &sentcount);
1446 /*printk("%d %d ", indcount, sentcount); */
1447 spk_reset_index_count(sentcount + 1);
1448 if (indcount == 1) {
1449 if (!say_sentence_num(sentcount + 1, 0)) {
1450 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1453 synth_insert_next_index(0);
1456 if (!say_sentence_num(sentcount + 1, 1)) {
1458 spk_reset_index_count(sn);
1460 synth_insert_next_index(0);
1462 if (!say_sentence_num(sn, 0)) {
1463 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1466 synth_insert_next_index(0);
1468 start_read_all_timer(vc, RA_TIMER);
1478 if (get_sentence_buf(vc, 0) == -1) {
1479 kbd_fakekey2(vc, RA_DOWN_ARROW);
1481 say_sentence_num(0, 0);
1482 synth_insert_next_index(0);
1483 start_read_all_timer(vc, RA_TIMER);
1486 case RA_FIND_NEXT_SENT:
1487 rv = get_sentence_buf(vc, 0);
1491 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1493 say_sentence_num(1, 0);
1494 synth_insert_next_index(0);
1495 start_read_all_timer(vc, RA_TIMER);
1498 case RA_FIND_PREV_SENT:
1501 spk_get_index_count(&indcount, &sentcount);
1503 kbd_fakekey2(vc, RA_DOWN_ARROW);
1505 start_read_all_timer(vc, RA_TIMER);
1510 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1512 unsigned long flags;
1514 spin_lock_irqsave(&speakup_info.spinlock, flags);
1515 if (cursor_track == read_all_mode) {
1517 if (!synth || up_flag || spk_shut_up) {
1518 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1521 del_timer(&cursor_timer);
1522 spk_shut_up &= 0xfe;
1524 start_read_all_timer(vc, value + 1);
1525 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1528 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1532 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1534 unsigned long flags;
1535 struct var_t *cursor_timeout;
1537 spin_lock_irqsave(&speakup_info.spinlock, flags);
1539 if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1540 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1543 spk_shut_up &= 0xfe;
1546 /* the key press flushes if !no_inter but we want to flush on cursor
1547 * moves regardless of no_inter state
1549 is_cursor = value + 1;
1550 old_cursor_pos = vc->vc_pos;
1551 old_cursor_x = vc->state.x;
1552 old_cursor_y = vc->state.y;
1553 speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1554 cursor_con = vc->vc_num;
1555 if (cursor_track == CT_Highlight)
1556 reset_highlight_buffers(vc);
1557 cursor_timeout = spk_get_var(CURSOR_TIME);
1558 mod_timer(&cursor_timer,
1559 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1560 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1563 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1566 int vc_num = vc->vc_num;
1568 bi = (vc->vc_attr & 0x70) >> 4;
1569 hi = speakup_console[vc_num]->ht.highsize[bi];
1572 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1573 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1574 speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1575 speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1577 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1579 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1581 } else if ((ic[i] == 32) && (hi != 0)) {
1582 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1584 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1591 speakup_console[vc_num]->ht.highsize[bi] = hi;
1594 static void reset_highlight_buffers(struct vc_data *vc)
1597 int vc_num = vc->vc_num;
1599 for (i = 0; i < 8; i++)
1600 speakup_console[vc_num]->ht.highsize[i] = 0;
1603 static int count_highlight_color(struct vc_data *vc)
1607 int vc_num = vc->vc_num;
1609 u16 *start = (u16 *)vc->vc_origin;
1611 for (i = 0; i < 8; i++)
1612 speakup_console[vc_num]->ht.bgcount[i] = 0;
1614 for (i = 0; i < vc->vc_rows; i++) {
1615 u16 *end = start + vc->vc_cols * 2;
1618 for (ptr = start; ptr < end; ptr++) {
1619 ch = get_attributes(vc, ptr);
1620 bg = (ch & 0x70) >> 4;
1621 speakup_console[vc_num]->ht.bgcount[bg]++;
1623 start += vc->vc_size_row;
1627 for (i = 0; i < 8; i++)
1628 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1633 static int get_highlight_color(struct vc_data *vc)
1636 unsigned int cptr[8];
1637 int vc_num = vc->vc_num;
1639 for (i = 0; i < 8; i++)
1642 for (i = 0; i < 7; i++)
1643 for (j = i + 1; j < 8; j++)
1644 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1645 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1646 swap(cptr[i], cptr[j]);
1648 for (i = 0; i < 8; i++)
1649 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1650 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1655 static int speak_highlight(struct vc_data *vc)
1658 int vc_num = vc->vc_num;
1660 if (count_highlight_color(vc) == 1)
1662 hc = get_highlight_color(vc);
1664 d = vc->state.y - speakup_console[vc_num]->ht.cy;
1665 if ((d == 1) || (d == -1))
1666 if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1670 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1671 speakup_console[vc_num]->ht.highsize[hc]);
1672 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1673 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1674 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1680 static void cursor_done(struct timer_list *unused)
1682 struct vc_data *vc = vc_cons[cursor_con].d;
1683 unsigned long flags;
1685 del_timer(&cursor_timer);
1686 spin_lock_irqsave(&speakup_info.spinlock, flags);
1687 if (cursor_con != fg_console) {
1693 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1694 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1700 if (cursor_track == read_all_mode) {
1701 handle_cursor_read_all(vc, read_all_key);
1704 if (cursor_track == CT_Highlight) {
1705 if (speak_highlight(vc)) {
1711 if (cursor_track == CT_Window)
1712 speakup_win_say(vc);
1713 else if (is_cursor == 1 || is_cursor == 4)
1714 say_line_from_to(vc, 0, vc->vc_cols, 0);
1720 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1723 /* called by: vt_notifier_call() */
1724 static void speakup_bs(struct vc_data *vc)
1726 unsigned long flags;
1728 if (!speakup_console[vc->vc_num])
1730 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1731 /* Speakup output, discard */
1735 if (spk_shut_up || !synth) {
1736 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1739 if (vc->vc_num == fg_console && spk_keydown) {
1744 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1747 /* called by: vt_notifier_call() */
1748 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1750 unsigned long flags;
1752 if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1754 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1755 /* Speakup output, discard */
1757 if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1759 if ((is_cursor) || (cursor_track == read_all_mode)) {
1760 if (cursor_track == CT_Highlight)
1761 update_color_buffer(vc, str, len);
1762 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1766 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1767 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1768 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1773 spkup_write(str, len);
1774 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1777 static void speakup_con_update(struct vc_data *vc)
1779 unsigned long flags;
1781 if (!speakup_console[vc->vc_num] || spk_parked)
1783 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1784 /* Speakup output, discard */
1787 if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1788 synth_printf("%s", spk_str_pause);
1791 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1794 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1796 unsigned long flags;
1800 if (!synth || up_flag || spk_killed)
1802 spin_lock_irqsave(&speakup_info.spinlock, flags);
1803 spk_shut_up &= 0xfe;
1808 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1809 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1812 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1813 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1816 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1817 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1818 if (speakup_console[vc->vc_num])
1819 speakup_console[vc->vc_num]->tty_stopped = on_off;
1823 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1827 synth_printf("%s %s\n",
1828 label, spk_msg_get(MSG_STATUS_START + on_off));
1829 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1832 static int inc_dec_var(u_char value)
1834 struct st_var_header *p_header;
1835 struct var_t *var_data;
1839 int var_id = (int)value - VAR_START;
1840 int how = (var_id & 1) ? E_INC : E_DEC;
1842 var_id = var_id / 2 + FIRST_SET_VAR;
1843 p_header = spk_get_var_header(var_id);
1846 if (p_header->var_type != VAR_NUM)
1848 var_data = p_header->data;
1849 if (spk_set_num_var(1, p_header, how) != 0)
1851 if (!spk_close_press) {
1852 for (pn = p_header->name; *pn; pn++) {
1859 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1860 var_data->u.n.value);
1861 synth_printf("%s", num_buf);
1865 static void speakup_win_set(struct vc_data *vc)
1869 if (win_start > 1) {
1870 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1873 if (spk_x < win_left || spk_y < win_top) {
1874 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1877 if (win_start && spk_x == win_left && spk_y == win_top) {
1879 win_right = vc->vc_cols - 1;
1881 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1891 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1893 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1894 (int)spk_y + 1, (int)spk_x + 1);
1896 synth_printf("%s\n", info);
1900 static void speakup_win_clear(struct vc_data *vc)
1907 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1910 static void speakup_win_enable(struct vc_data *vc)
1912 if (win_start < 2) {
1913 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1918 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1920 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1923 static void speakup_bits(struct vc_data *vc)
1925 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1927 if (spk_special_handler || val < 1 || val > 6) {
1928 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1931 pb_edit = &spk_punc_info[val];
1932 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1933 spk_special_handler = edit_bits;
1936 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1938 static u_char goto_buf[8];
1944 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1946 if (type == KT_LATIN && ch == '\n')
1955 wch = goto_buf[--num];
1956 goto_buf[num] = '\0';
1957 spkup_write(&wch, 1);
1960 if (ch < '+' || ch > 'y')
1963 goto_buf[num++] = ch;
1964 goto_buf[num] = '\0';
1965 spkup_write(&wch, 1);
1966 maxlen = (*goto_buf >= '0') ? 3 : 4;
1967 if ((ch == '+' || ch == '-') && num == 1)
1969 if (ch >= '0' && ch <= '9' && num < maxlen)
1971 if (num < maxlen - 1 || num > maxlen)
1973 if (ch < 'x' || ch > 'y') {
1976 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1977 goto_buf[num = 0] = '\0';
1978 spk_special_handler = NULL;
1982 /* Do not replace with kstrtoul: here we need cp to be updated */
1983 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1986 if (*goto_buf < '0')
1988 else if (goto_pos > 0)
1991 if (goto_pos >= vc->vc_cols)
1992 goto_pos = vc->vc_cols - 1;
1995 if (*goto_buf < '0')
1997 else if (goto_pos > 0)
2000 if (goto_pos >= vc->vc_rows)
2001 goto_pos = vc->vc_rows - 1;
2004 goto_buf[num = 0] = '\0';
2006 spk_special_handler = NULL;
2009 spk_pos -= spk_x * 2;
2011 spk_pos += goto_pos * 2;
2015 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2021 static void speakup_goto(struct vc_data *vc)
2023 if (spk_special_handler) {
2024 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2027 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2028 spk_special_handler = handle_goto;
2031 static void speakup_help(struct vc_data *vc)
2033 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2036 static void do_nothing(struct vc_data *vc)
2038 return; /* flush done in do_spkup */
2041 static u_char key_speakup, spk_key_locked;
2043 static void speakup_lock(struct vc_data *vc)
2045 if (!spk_key_locked) {
2046 spk_key_locked = 16;
2054 typedef void (*spkup_hand) (struct vc_data *);
2055 static spkup_hand spkup_handler[] = {
2056 /* must be ordered same as defines in speakup.h */
2057 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2058 speakup_cut, speakup_paste, say_first_char, say_last_char,
2059 say_char, say_prev_char, say_next_char,
2060 say_word, say_prev_word, say_next_word,
2061 say_line, say_prev_line, say_next_line,
2062 top_edge, bottom_edge, left_edge, right_edge,
2063 spell_word, spell_word, say_screen,
2064 say_position, say_attributes,
2065 speakup_off, speakup_parked, say_line, /* this is for indent */
2066 say_from_top, say_to_bottom,
2067 say_from_left, say_to_right,
2068 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2069 speakup_bits, speakup_bits, speakup_bits,
2070 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2071 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2074 static void do_spkup(struct vc_data *vc, u_char value)
2076 if (spk_killed && value != SPEECH_KILL)
2080 spk_shut_up &= 0xfe;
2081 this_speakup_key = value;
2082 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2084 (*spkup_handler[value]) (vc);
2086 if (inc_dec_var(value) < 0)
2091 static const char *pad_chars = "0123456789+-*/\015,.?()";
2094 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2097 unsigned long flags;
2100 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2101 u_char shift_info, offset;
2107 spin_lock_irqsave(&speakup_info.spinlock, flags);
2111 if (type == KT_PAD &&
2112 (vt_get_leds(fg_console, VC_NUMLOCK))) {
2117 value = pad_chars[value];
2118 spk_lastkey = value;
2123 if (keycode >= MAX_KEY)
2125 key_info = spk_our_keys[keycode];
2128 /* Check valid read all mode keys */
2129 if ((cursor_track == read_all_mode) && (!up_flag)) {
2143 shift_info = (shift_state & 0x0f) + key_speakup;
2144 offset = spk_shift_table[shift_info];
2146 new_key = key_info[offset];
2149 if (new_key == SPK_KEY) {
2150 if (!spk_key_locked)
2151 key_speakup = (up_flag) ? 0 : 16;
2152 if (up_flag || spk_killed)
2154 spk_shut_up &= 0xfe;
2160 if (last_keycode == keycode &&
2161 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2162 spk_close_press = 1;
2163 offset = spk_shift_table[shift_info + 32];
2165 if (offset && key_info[offset])
2166 new_key = key_info[offset];
2168 last_keycode = keycode;
2169 last_spk_jiffy = jiffies;
2175 if (type == KT_SPKUP && !spk_special_handler) {
2176 do_spkup(vc, new_key);
2177 spk_close_press = 0;
2181 if (up_flag || spk_killed || type == KT_SHIFT)
2183 spk_shut_up &= 0xfe;
2184 kh = (value == KVAL(K_DOWN)) ||
2185 (value == KVAL(K_UP)) ||
2186 (value == KVAL(K_LEFT)) ||
2187 (value == KVAL(K_RIGHT));
2188 if ((cursor_track != read_all_mode) || !kh)
2191 if (spk_special_handler) {
2192 if (type == KT_SPEC && value == 1) {
2195 } else if (type == KT_LETTER) {
2197 } else if (value == 0x7f) {
2198 value = 8; /* make del = backspace */
2200 ret = (*spk_special_handler) (vc, type, value, keycode);
2201 spk_close_press = 0;
2208 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2212 static int keyboard_notifier_call(struct notifier_block *nb,
2213 unsigned long code, void *_param)
2215 struct keyboard_notifier_param *param = _param;
2216 struct vc_data *vc = param->vc;
2217 int up = !param->down;
2218 int ret = NOTIFY_OK;
2219 static int keycode; /* to hold the current keycode */
2221 in_keyboard_notifier = 1;
2223 if (vc->vc_mode == KD_GRAPHICS)
2227 * First, determine whether we are handling a fake keypress on
2228 * the current processor. If we are, then return NOTIFY_OK,
2229 * to pass the keystroke up the chain. This prevents us from
2230 * trying to take the Speakup lock while it is held by the
2231 * processor on which the simulated keystroke was generated.
2232 * Also, the simulated keystrokes should be ignored by Speakup.
2235 if (speakup_fake_key_pressed())
2240 /* speakup requires keycode and keysym currently */
2241 keycode = param->value;
2243 case KBD_UNBOUND_KEYCODE:
2250 if (speakup_key(vc, param->shift, keycode, param->value, up))
2252 else if (KTYP(param->value) == KT_CUR)
2253 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2255 case KBD_POST_KEYSYM:{
2256 unsigned char type = KTYP(param->value) - 0xf0;
2257 unsigned char val = KVAL(param->value);
2261 do_handle_shift(vc, val, up);
2265 do_handle_latin(vc, val, up);
2268 do_handle_cursor(vc, val, up);
2271 do_handle_spec(vc, val, up);
2278 in_keyboard_notifier = 0;
2282 static int vt_notifier_call(struct notifier_block *nb,
2283 unsigned long code, void *_param)
2285 struct vt_notifier_param *param = _param;
2286 struct vc_data *vc = param->vc;
2290 if (vc->vc_mode == KD_TEXT)
2291 speakup_allocate(vc, GFP_ATOMIC);
2294 speakup_deallocate(vc);
2297 if (param->c == '\b') {
2302 speakup_con_write(vc, &d, 1);
2306 speakup_con_update(vc);
2312 /* called by: module_exit() */
2313 static void __exit speakup_exit(void)
2317 unregister_keyboard_notifier(&keyboard_notifier_block);
2318 unregister_vt_notifier(&vt_notifier_block);
2319 speakup_unregister_devsynth();
2320 speakup_cancel_selection();
2321 speakup_cancel_paste();
2322 del_timer_sync(&cursor_timer);
2323 kthread_stop(speakup_task);
2324 speakup_task = NULL;
2325 mutex_lock(&spk_mutex);
2327 mutex_unlock(&spk_mutex);
2328 spk_ttyio_unregister_ldisc();
2330 speakup_kobj_exit();
2332 for (i = 0; i < MAX_NR_CONSOLES; i++)
2333 kfree(speakup_console[i]);
2335 speakup_remove_virtual_keyboard();
2337 for (i = 0; i < MAXVARS; i++)
2338 speakup_unregister_var(i);
2340 for (i = 0; i < 256; i++) {
2341 if (spk_characters[i] != spk_default_chars[i])
2342 kfree(spk_characters[i]);
2345 spk_free_user_msgs();
2348 /* call by: module_init() */
2349 static int __init speakup_init(void)
2353 struct vc_data *vc = vc_cons[fg_console].d;
2356 /* These first few initializations cannot fail. */
2357 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2358 spk_reset_default_chars();
2359 spk_reset_default_chartab();
2360 spk_strlwr(synth_name);
2361 spk_vars[0].u.n.high = vc->vc_cols;
2362 for (var = spk_vars; var->var_id != MAXVARS; var++)
2363 speakup_register_var(var);
2364 for (var = synth_time_vars;
2365 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2366 speakup_register_var(var);
2367 for (i = 1; spk_punc_info[i].mask != 0; i++)
2368 spk_set_mask_bits(NULL, i, 2);
2370 spk_set_key_info(spk_key_defaults, spk_key_buf);
2372 /* From here on out, initializations can fail. */
2373 err = speakup_add_virtual_keyboard();
2375 goto error_virtkeyboard;
2377 for (i = 0; i < MAX_NR_CONSOLES; i++)
2379 err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2381 goto error_kobjects;
2385 spk_shut_up |= 0x01;
2387 err = speakup_kobj_init();
2389 goto error_kobjects;
2391 spk_ttyio_register_ldisc();
2392 synth_init(synth_name);
2393 speakup_register_devsynth();
2395 * register_devsynth might fail, but this error is not fatal.
2396 * /dev/synth is an extra feature; the rest of Speakup
2397 * will work fine without it.
2400 err = register_keyboard_notifier(&keyboard_notifier_block);
2402 goto error_kbdnotifier;
2403 err = register_vt_notifier(&vt_notifier_block);
2405 goto error_vtnotifier;
2407 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2409 if (IS_ERR(speakup_task)) {
2410 err = PTR_ERR(speakup_task);
2414 set_user_nice(speakup_task, 10);
2415 wake_up_process(speakup_task);
2417 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2418 pr_info("synth name on entry is: %s\n", synth_name);
2422 unregister_vt_notifier(&vt_notifier_block);
2425 unregister_keyboard_notifier(&keyboard_notifier_block);
2426 del_timer(&cursor_timer);
2429 speakup_unregister_devsynth();
2430 mutex_lock(&spk_mutex);
2432 mutex_unlock(&spk_mutex);
2433 speakup_kobj_exit();
2436 for (i = 0; i < MAX_NR_CONSOLES; i++)
2437 kfree(speakup_console[i]);
2439 speakup_remove_virtual_keyboard();
2442 for (i = 0; i < MAXVARS; i++)
2443 speakup_unregister_var(i);
2445 for (i = 0; i < 256; i++) {
2446 if (spk_characters[i] != spk_default_chars[i])
2447 kfree(spk_characters[i]);
2450 spk_free_user_msgs();
2456 module_init(speakup_init);
2457 module_exit(speakup_exit);