2 * review functions for the speakup screen review package.
3 * originally written by: Kirk Reiser and Andy Berdan.
5 * extensively modified by David Borowski.
7 ** Copyright (C) 1998 Kirk Reiser.
8 * Copyright (C) 2003 David Borowski.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
21 #include <linux/kernel.h>
23 #include <linux/tty.h>
24 #include <linux/mm.h> /* __get_free_page() and friends */
25 #include <linux/vt_kern.h>
26 #include <linux/ctype.h>
27 #include <linux/selection.h>
28 #include <linux/unistd.h>
29 #include <linux/jiffies.h>
30 #include <linux/kthread.h>
31 #include <linux/keyboard.h> /* for KT_SHIFT */
32 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
33 #include <linux/input.h>
34 #include <linux/kmod.h>
36 /* speakup_*_selection */
37 #include <linux/module.h>
38 #include <linux/sched.h>
39 #include <linux/slab.h>
40 #include <linux/types.h>
41 #include <linux/consolemap.h>
43 #include <linux/spinlock.h>
44 #include <linux/notifier.h>
46 #include <linux/uaccess.h> /* copy_from|to|user() and others */
51 #define MAX_DELAY msecs_to_jiffies(500)
52 #define MINECHOCHAR SPACE
54 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
55 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
56 MODULE_DESCRIPTION("Speakup console speech");
57 MODULE_LICENSE("GPL");
58 MODULE_VERSION(SPEAKUP_VERSION);
61 module_param_named(synth, synth_name, charp, 0444);
62 module_param_named(quiet, spk_quiet_boot, bool, 0444);
64 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
65 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
67 special_func spk_special_handler;
69 short spk_pitch_shift, synth_flags;
71 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
72 int spk_no_intr, spk_spell_delay;
73 int spk_key_echo, spk_say_word_ctl;
74 int spk_say_ctrl, spk_bell_pos;
76 int spk_punc_level, spk_reading_punc;
77 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
78 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
79 const struct st_bits_data spk_punc_info[] = {
81 {"some", "/$%&@", SOME},
82 {"most", "$%&#()=+*/@^<>|\\", MOST},
83 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
84 {"delimiters", "", B_WDLM},
85 {"repeats", "()", CH_RPT},
86 {"extended numeric", "", B_EXNUM},
87 {"symbols", "", B_SYM},
91 static char mark_cut_flag;
93 static u_char *spk_shift_table;
94 u_char *spk_our_keys[MAX_KEY];
95 u_char spk_key_buf[600];
96 const u_char spk_key_defaults[] = {
97 #include "speakupmap.h"
100 /* Speakup Cursor Track Variables */
101 static int cursor_track = 1, prev_cursor_track = 1;
103 /* cursor track modes, must be ordered same as cursor_msgs */
112 #define read_all_mode CT_Max
114 static struct tty_struct *tty;
116 static void spkup_write(const u16 *in_buf, int count);
118 static char *phonetic[] = {
119 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
120 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
122 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
123 "x ray", "yankee", "zulu"
126 /* array of 256 char pointers (one for each character description)
127 * initialized to default_chars and user selectable via
128 * /proc/speakup/characters
130 char *spk_characters[256];
132 char *spk_default_chars[256] = {
133 /*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
134 /*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
135 /*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
136 /*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
138 /*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
140 /*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
143 /*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
145 /*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
146 /*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
147 /*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
148 /*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
149 /*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
152 /*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
153 /*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
154 /*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
155 /*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
156 /*127*/ "del", "control", "control", "control", "control", "control",
157 "control", "control", "control", "control", "control",
158 /*138*/ "control", "control", "control", "control", "control",
159 "control", "control", "control", "control", "control",
160 "control", "control",
161 /*150*/ "control", "control", "control", "control", "control",
162 "control", "control", "control", "control", "control",
163 /*160*/ "nbsp", "inverted bang",
164 /*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
165 /*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
166 /*172*/ "not", "soft hyphen", "registered", "macron",
167 /*176*/ "degrees", "plus or minus", "super two", "super three",
168 /*180*/ "acute accent", "micro", "pilcrow", "middle dot",
169 /*184*/ "cedilla", "super one", "male ordinal", "double right angle",
170 /*188*/ "one quarter", "one half", "three quarters",
172 /*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
174 /*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
176 /*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
178 /*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
179 /*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
181 /*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
182 /*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
183 /*230*/ "ae", "c cidella", "e grave", "e acute",
184 /*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
186 /*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
188 /*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
190 /* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
193 /* array of 256 u_short (one for each character)
194 * initialized to default_chartab and user selectable via
195 * /sys/module/speakup/parameters/chartab
197 u_short spk_chartab[256];
199 static u_short default_chartab[256] = {
200 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
201 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
202 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
203 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
204 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
205 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
206 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
207 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
208 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
209 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
210 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
211 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
212 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
213 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
214 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
215 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
216 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
218 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
220 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
222 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
224 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
226 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
227 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
228 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
229 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
230 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
231 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
232 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
233 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
234 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
235 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
236 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
239 struct task_struct *speakup_task;
240 struct bleep spk_unprocessed_sound;
241 static int spk_keydown;
242 static u16 spk_lastkey;
243 static u_char spk_close_press, keymap_flags;
244 static u_char last_keycode, this_speakup_key;
245 static u_long last_spk_jiffy;
247 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
249 DEFINE_MUTEX(spk_mutex);
251 static int keyboard_notifier_call(struct notifier_block *,
252 unsigned long code, void *param);
254 static struct notifier_block keyboard_notifier_block = {
255 .notifier_call = keyboard_notifier_call,
258 static int vt_notifier_call(struct notifier_block *,
259 unsigned long code, void *param);
261 static struct notifier_block vt_notifier_block = {
262 .notifier_call = vt_notifier_call,
265 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
267 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
268 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
271 static void speakup_date(struct vc_data *vc)
273 spk_x = spk_cx = vc->vc_x;
274 spk_y = spk_cy = vc->vc_y;
275 spk_pos = spk_cp = vc->vc_pos;
276 spk_old_attr = spk_attr;
277 spk_attr = get_attributes(vc, (u_short *)spk_pos);
280 static void bleep(u_short val)
282 static const short vals[] = {
283 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
286 int time = spk_bleep_time;
288 freq = vals[val % 12];
290 freq *= (1 << (val / 12));
291 spk_unprocessed_sound.freq = freq;
292 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
293 spk_unprocessed_sound.active = 1;
294 /* We can only have 1 active sound at a time. */
297 static void speakup_shut_up(struct vc_data *vc)
308 static void speech_kill(struct vc_data *vc)
310 char val = synth->is_alive(synth);
315 /* re-enables synth, if disabled */
316 if (val == 2 || spk_killed) {
318 spk_shut_up &= ~0x40;
319 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
321 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
326 static void speakup_off(struct vc_data *vc)
328 if (spk_shut_up & 0x80) {
330 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
333 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
338 static void speakup_parked(struct vc_data *vc)
340 if (spk_parked & 0x80) {
342 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
345 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
349 static void speakup_cut(struct vc_data *vc)
351 static const char err_buf[] = "set selection failed";
354 if (!mark_cut_flag) {
356 spk_xs = (u_short)spk_x;
357 spk_ys = (u_short)spk_y;
359 synth_printf("%s\n", spk_msg_get(MSG_MARK));
362 spk_xe = (u_short)spk_x;
363 spk_ye = (u_short)spk_y;
365 synth_printf("%s\n", spk_msg_get(MSG_CUT));
367 speakup_clear_selection();
368 ret = speakup_set_selection(tty);
372 break; /* no error */
374 pr_warn("%sEFAULT\n", err_buf);
377 pr_warn("%sEINVAL\n", err_buf);
380 pr_warn("%sENOMEM\n", err_buf);
385 static void speakup_paste(struct vc_data *vc)
389 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
391 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
392 speakup_paste_selection(tty);
396 static void say_attributes(struct vc_data *vc)
398 int fg = spk_attr & 0x0f;
399 int bg = spk_attr >> 4;
402 synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
405 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
407 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
410 synth_printf(" %s ", spk_msg_get(MSG_ON));
412 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
423 static void announce_edge(struct vc_data *vc, int msg_id)
427 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
429 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
432 static void speak_char(u16 ch)
435 struct var_t *direct = spk_get_var(DIRECT);
437 if (ch >= 0x100 || (direct && direct->u.n.value)) {
438 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
440 synth_printf("%s", spk_str_caps_start);
443 if (ch < 0x100 && IS_CHAR(ch, B_CAP))
444 synth_printf("%s", spk_str_caps_stop);
448 cp = spk_characters[ch];
450 pr_info("speak_char: cp == NULL!\n");
453 if (IS_CHAR(ch, B_CAP)) {
455 synth_printf("%s %s %s",
456 spk_str_caps_start, cp, spk_str_caps_stop);
460 synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
462 synth_printf(" %s ", cp);
466 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
474 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, 1);
478 if (w & vc->vc_hi_font_mask) {
479 w &= ~vc->vc_hi_font_mask;
483 ch = inverse_translate(vc, c, 1);
484 *attribs = (w & 0xff00) >> 8;
489 static void say_char(struct vc_data *vc)
493 spk_old_attr = spk_attr;
494 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
495 if (spk_attr != spk_old_attr) {
496 if (spk_attrib_bleep & 1)
498 if (spk_attrib_bleep & 2)
504 static void say_phonetic_char(struct vc_data *vc)
508 spk_old_attr = spk_attr;
509 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
510 if (ch <= 0x7f && isalpha(ch)) {
512 synth_printf("%s\n", phonetic[--ch]);
514 if (ch < 0x100 && IS_CHAR(ch, B_NUM))
515 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
520 static void say_prev_char(struct vc_data *vc)
524 announce_edge(vc, edge_left);
532 static void say_next_char(struct vc_data *vc)
535 if (spk_x == vc->vc_cols - 1) {
536 announce_edge(vc, edge_right);
544 /* get_word - will first check to see if the character under the
545 * reading cursor is a space and if spk_say_word_ctl is true it will
546 * return the word space. If spk_say_word_ctl is not set it will check to
547 * see if there is a word starting on the next position to the right
548 * and return that word if it exists. If it does not exist it will
549 * move left to the beginning of any previous word on the line or the
550 * beginning off the line whichever comes first..
553 static u_long get_word(struct vc_data *vc)
555 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
560 spk_old_attr = spk_attr;
561 ch = get_char(vc, (u_short *)tmp_pos, &temp);
563 /* decided to take out the sayword if on a space (mis-information */
564 if (spk_say_word_ctl && ch == SPACE) {
566 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
568 } else if (tmpx < vc->vc_cols - 2 &&
569 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
570 get_char(vc, (u_short *)&tmp_pos + 1, &temp) > SPACE) {
575 ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
576 if ((ch == SPACE || ch == 0 ||
577 (ch < 0x100 && IS_WDLM(ch))) &&
578 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
583 attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
584 buf[cnt++] = attr_ch;
585 while (tmpx < vc->vc_cols - 1) {
588 ch = get_char(vc, (u_short *)tmp_pos, &temp);
589 if (ch == SPACE || ch == 0 ||
590 (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
599 static void say_word(struct vc_data *vc)
601 u_long cnt = get_word(vc);
602 u_short saved_punc_mask = spk_punc_mask;
606 spk_punc_mask = PUNC;
608 spkup_write(buf, cnt);
609 spk_punc_mask = saved_punc_mask;
612 static void say_prev_word(struct vc_data *vc)
616 u_short edge_said = 0, last_state = 0, state = 0;
622 announce_edge(vc, edge_top);
627 edge_said = edge_quiet;
632 edge_said = edge_top;
635 if (edge_said != edge_quiet)
636 edge_said = edge_left;
640 spk_x = vc->vc_cols - 1;
645 ch = get_char(vc, (u_short *)spk_pos, &temp);
646 if (ch == SPACE || ch == 0)
648 else if (ch < 0x100 && IS_WDLM(ch))
652 if (state < last_state) {
659 if (spk_x == 0 && edge_said == edge_quiet)
660 edge_said = edge_left;
661 if (edge_said > 0 && edge_said < edge_quiet)
662 announce_edge(vc, edge_said);
666 static void say_next_word(struct vc_data *vc)
670 u_short edge_said = 0, last_state = 2, state = 0;
673 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
674 announce_edge(vc, edge_bottom);
678 ch = get_char(vc, (u_short *)spk_pos, &temp);
679 if (ch == SPACE || ch == 0)
681 else if (ch < 0x100 && IS_WDLM(ch))
685 if (state > last_state)
687 if (spk_x >= vc->vc_cols - 1) {
688 if (spk_y == vc->vc_rows - 1) {
689 edge_said = edge_bottom;
695 edge_said = edge_right;
703 announce_edge(vc, edge_said);
707 static void spell_word(struct vc_data *vc)
709 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
712 char *str_cap = spk_str_caps_stop;
713 char *last_cap = spk_str_caps_stop;
714 struct var_t *direct = spk_get_var(DIRECT);
721 synth_printf(" %s ", delay_str[spk_spell_delay]);
722 /* FIXME: Non-latin1 considered as lower case */
723 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
724 str_cap = spk_str_caps_start;
725 if (*spk_str_caps_stop)
727 else /* synth has no pitch */
728 last_cap = spk_str_caps_stop;
730 str_cap = spk_str_caps_stop;
732 if (str_cap != last_cap) {
733 synth_printf("%s", str_cap);
736 if (ch >= 0x100 || (direct && direct->u.n.value)) {
738 } else if (this_speakup_key == SPELL_PHONETIC &&
739 ch <= 0x7f && isalpha(ch)) {
741 cp1 = phonetic[--ch];
742 synth_printf("%s", cp1);
744 cp1 = spk_characters[ch];
746 synth_printf("%s", spk_msg_get(MSG_CTRL));
749 synth_printf("%s", cp1);
753 if (str_cap != spk_str_caps_stop)
754 synth_printf("%s", spk_str_caps_stop);
757 static int get_line(struct vc_data *vc)
759 u_long tmp = spk_pos - (spk_x * 2);
763 spk_old_attr = spk_attr;
764 spk_attr = get_attributes(vc, (u_short *)spk_pos);
765 for (i = 0; i < vc->vc_cols; i++) {
766 buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
769 for (--i; i >= 0; i--)
775 static void say_line(struct vc_data *vc)
777 int i = get_line(vc);
779 u_short saved_punc_mask = spk_punc_mask;
782 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
786 if (this_speakup_key == SAY_LINE_INDENT) {
790 synth_printf("%zd, ", (cp - buf) + 1);
792 spk_punc_mask = spk_punc_masks[spk_reading_punc];
794 spk_punc_mask = saved_punc_mask;
797 static void say_prev_line(struct vc_data *vc)
801 announce_edge(vc, edge_top);
805 spk_pos -= vc->vc_size_row;
809 static void say_next_line(struct vc_data *vc)
812 if (spk_y == vc->vc_rows - 1) {
813 announce_edge(vc, edge_bottom);
817 spk_pos += vc->vc_size_row;
821 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
826 u_short saved_punc_mask = spk_punc_mask;
828 spk_old_attr = spk_attr;
829 spk_attr = get_attributes(vc, (u_short *)from);
831 buf[i++] = get_char(vc, (u_short *)from, &tmp);
833 if (i >= vc->vc_size_row)
836 for (--i; i >= 0; i--)
844 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
847 spk_punc_mask = saved_punc_mask;
851 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
854 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
855 u_long end = start + (to * 2);
858 if (say_from_to(vc, start, end, read_punc) <= 0)
859 if (cursor_track != read_all_mode)
860 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
863 /* Sentence Reading Commands */
865 static int currsentence;
866 static int numsentences[2];
867 static u16 *sentbufend[2];
868 static u16 *sentmarks[2][10];
871 static u16 sentbuf[2][256];
873 static int say_sentence_num(int num, int prev)
876 currsentence = num + 1;
877 if (prev && --bn == -1)
880 if (num > numsentences[bn])
883 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
887 static int get_sentence_buf(struct vc_data *vc, int read_punc)
897 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
898 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
900 numsentences[bn] = 0;
901 sentmarks[bn][0] = &sentbuf[bn][0];
903 spk_old_attr = spk_attr;
904 spk_attr = get_attributes(vc, (u_short *)start);
906 while (start < end) {
907 sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
909 if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.' &&
910 numsentences[bn] < 9) {
911 /* Sentence Marker */
913 sentmarks[bn][numsentences[bn]] =
919 if (i >= vc->vc_size_row)
923 for (--i; i >= 0; i--)
924 if (sentbuf[bn][i] != SPACE)
930 sentbuf[bn][++i] = SPACE;
931 sentbuf[bn][++i] = '\0';
933 sentbufend[bn] = &sentbuf[bn][i];
934 return numsentences[bn];
937 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
939 u_long start = vc->vc_origin, end;
942 start += from * vc->vc_size_row;
943 if (to > vc->vc_rows)
945 end = vc->vc_origin + (to * vc->vc_size_row);
946 for (from = start; from < end; from = to) {
947 to = from + vc->vc_size_row;
948 say_from_to(vc, from, to, 1);
952 static void say_screen(struct vc_data *vc)
954 say_screen_from_to(vc, 0, vc->vc_rows);
957 static void speakup_win_say(struct vc_data *vc)
959 u_long start, end, from, to;
962 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
965 start = vc->vc_origin + (win_top * vc->vc_size_row);
966 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
967 while (start <= end) {
968 from = start + (win_left * 2);
969 to = start + (win_right * 2);
970 say_from_to(vc, from, to, 1);
971 start += vc->vc_size_row;
975 static void top_edge(struct vc_data *vc)
978 spk_pos = vc->vc_origin + 2 * spk_x;
983 static void bottom_edge(struct vc_data *vc)
986 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
987 spk_y = vc->vc_rows - 1;
991 static void left_edge(struct vc_data *vc)
994 spk_pos -= spk_x * 2;
999 static void right_edge(struct vc_data *vc)
1002 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
1003 spk_x = vc->vc_cols - 1;
1007 static void say_first_char(struct vc_data *vc)
1009 int i, len = get_line(vc);
1014 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1017 for (i = 0; i < len; i++)
1018 if (buf[i] != SPACE)
1021 spk_pos -= (spk_x - i) * 2;
1023 synth_printf("%d, ", ++i);
1027 static void say_last_char(struct vc_data *vc)
1029 int len = get_line(vc);
1034 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1038 spk_pos -= (spk_x - len) * 2;
1040 synth_printf("%d, ", ++len);
1044 static void say_position(struct vc_data *vc)
1046 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1051 /* Added by brianb */
1052 static void say_char_num(struct vc_data *vc)
1055 u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1057 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1060 /* these are stub functions to keep keyboard.c happy. */
1062 static void say_from_top(struct vc_data *vc)
1064 say_screen_from_to(vc, 0, spk_y);
1067 static void say_to_bottom(struct vc_data *vc)
1069 say_screen_from_to(vc, spk_y, vc->vc_rows);
1072 static void say_from_left(struct vc_data *vc)
1074 say_line_from_to(vc, 0, spk_x, 1);
1077 static void say_to_right(struct vc_data *vc)
1079 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1082 /* end of stub functions. */
1084 static void spkup_write(const u16 *in_buf, int count)
1086 static int rep_count;
1087 static u16 ch = '\0', old_ch = '\0';
1088 static u_short char_type, last_type;
1089 int in_count = count;
1093 if (cursor_track == read_all_mode) {
1094 /* Insert Sentence Index */
1095 if ((in_buf == sentmarks[bn][currsentence]) &&
1096 (currsentence <= numsentences[bn]))
1097 synth_insert_next_index(currsentence++);
1101 char_type = spk_chartab[ch];
1104 if (ch == old_ch && !(char_type & B_NUM)) {
1105 if (++rep_count > 2)
1108 if ((last_type & CH_RPT) && rep_count > 2) {
1110 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1116 if (ch == spk_lastkey) {
1118 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1120 } else if (char_type & B_ALPHA) {
1121 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1122 synth_buffer_add(SPACE);
1124 } else if (char_type & B_NUM) {
1127 } else if (char_type & spk_punc_mask) {
1129 char_type &= ~PUNC; /* for dec nospell processing */
1130 } else if (char_type & SYNTH_OK) {
1131 /* these are usually puncts like . and , which synth
1132 * needs for expression.
1133 * suppress multiple to get rid of long pauses and
1134 * clear repeat count
1136 * repeats on you don't get nothing repeated count
1143 /* send space and record position, if next is num overwrite space */
1145 synth_buffer_add(SPACE);
1150 last_type = char_type;
1153 if (in_count > 2 && rep_count > 2) {
1154 if (last_type & CH_RPT) {
1156 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1164 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1166 static void read_all_doc(struct vc_data *vc);
1167 static void cursor_done(u_long data);
1168 static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1170 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1172 unsigned long flags;
1174 if (!synth || up_flag || spk_killed)
1176 spin_lock_irqsave(&speakup_info.spinlock, flags);
1177 if (cursor_track == read_all_mode) {
1180 del_timer(&cursor_timer);
1181 spk_shut_up &= 0xfe;
1186 del_timer(&cursor_timer);
1187 cursor_track = prev_cursor_track;
1188 spk_shut_up &= 0xfe;
1193 spk_shut_up &= 0xfe;
1196 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1197 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1198 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1201 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1203 unsigned long flags;
1205 spin_lock_irqsave(&speakup_info.spinlock, flags);
1209 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1212 if (!synth || spk_killed) {
1213 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1216 spk_shut_up &= 0xfe;
1217 spk_lastkey = value;
1220 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1222 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1225 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1227 int i = 0, states, key_data_len;
1228 const u_char *cp = key_info;
1229 u_char *cp1 = k_buffer;
1230 u_char ch, version, num_keys;
1233 if (version != KEY_MAP_VER) {
1234 pr_debug("version found %d should be %d\n",
1235 version, KEY_MAP_VER);
1239 states = (int)cp[1];
1240 key_data_len = (states + 1) * (num_keys + 1);
1241 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1242 pr_debug("too many key_infos (%d over %u)\n",
1243 key_data_len + SHIFT_TBL_SIZE + 4, (unsigned int)(sizeof(spk_key_buf)));
1246 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1247 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1248 spk_shift_table = k_buffer;
1249 spk_our_keys[0] = spk_shift_table;
1250 cp1 += SHIFT_TBL_SIZE;
1251 memcpy(cp1, cp, key_data_len + 3);
1252 /* get num_keys, states and data */
1253 cp1 += 2; /* now pointing at shift states */
1254 for (i = 1; i <= states; i++) {
1256 if (ch >= SHIFT_TBL_SIZE) {
1257 pr_debug("(%d) not valid shift state (max_allowed = %d)\n", ch,
1261 spk_shift_table[ch] = i;
1263 keymap_flags = *cp1++;
1264 while ((ch = *cp1)) {
1265 if (ch >= MAX_KEY) {
1266 pr_debug("(%d), not valid key, (max_allowed = %d)\n", ch, MAX_KEY);
1269 spk_our_keys[ch] = cp1;
1275 static struct var_t spk_vars[] = {
1276 /* bell must be first to set high limit */
1277 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1278 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1279 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1280 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1281 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1282 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1283 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1284 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1285 {SAY_CONTROL, TOGGLE_0},
1286 {SAY_WORD_CTL, TOGGLE_0},
1287 {NO_INTERRUPT, TOGGLE_0},
1288 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1292 static void toggle_cursoring(struct vc_data *vc)
1294 if (cursor_track == read_all_mode)
1295 cursor_track = prev_cursor_track;
1296 if (++cursor_track >= CT_Max)
1298 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1301 void spk_reset_default_chars(void)
1305 /* First, free any non-default */
1306 for (i = 0; i < 256; i++) {
1307 if (spk_characters[i] &&
1308 (spk_characters[i] != spk_default_chars[i]))
1309 kfree(spk_characters[i]);
1312 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1315 void spk_reset_default_chartab(void)
1317 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1320 static const struct st_bits_data *pb_edit;
1322 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1324 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1326 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1329 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1330 spk_special_handler = NULL;
1333 if (mask < PUNC && !(ch_type & PUNC))
1335 spk_chartab[ch] ^= mask;
1337 synth_printf(" %s\n",
1338 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1339 spk_msg_get(MSG_OFF));
1343 /* Allocation concurrency is protected by the console semaphore */
1344 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1348 vc_num = vc->vc_num;
1349 if (!speakup_console[vc_num]) {
1350 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1352 if (!speakup_console[vc_num])
1355 } else if (!spk_parked) {
1362 static void speakup_deallocate(struct vc_data *vc)
1366 vc_num = vc->vc_num;
1367 kfree(speakup_console[vc_num]);
1368 speakup_console[vc_num] = NULL;
1371 static u_char is_cursor;
1372 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1373 static int cursor_con;
1375 static void reset_highlight_buffers(struct vc_data *);
1377 static int read_all_key;
1379 static void start_read_all_timer(struct vc_data *vc, int command);
1393 static void kbd_fakekey2(struct vc_data *vc, int command)
1395 del_timer(&cursor_timer);
1396 speakup_fake_down_arrow();
1397 start_read_all_timer(vc, command);
1400 static void read_all_doc(struct vc_data *vc)
1402 if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1404 if (!synth_supports_indexing())
1406 if (cursor_track != read_all_mode)
1407 prev_cursor_track = cursor_track;
1408 cursor_track = read_all_mode;
1409 spk_reset_index_count(0);
1410 if (get_sentence_buf(vc, 0) == -1) {
1411 kbd_fakekey2(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, int 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, int 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->vc_x;
1552 old_cursor_y = vc->vc_y;
1553 speakup_console[vc->vc_num]->ht.cy = vc->vc_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->vc_x;
1575 speakup_console[vc_num]->ht.ry[bi] = vc->vc_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->vc_y - speakup_console[vc_num]->ht.cy;
1665 if ((d == 1) || (d == -1))
1666 if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_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(u_long data)
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->vc_x >= win_left && vc->vc_x <= win_right &&
1694 vc->vc_y >= win_top && vc->vc_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->vc_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->vc_x >= win_left && vc->vc_x <= win_right &&
1767 vc->vc_y >= win_top && vc->vc_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 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1790 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1792 unsigned long flags;
1796 if (!synth || up_flag || spk_killed)
1798 spin_lock_irqsave(&speakup_info.spinlock, flags);
1799 spk_shut_up &= 0xfe;
1804 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1805 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1808 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1809 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1812 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1813 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1814 if (speakup_console[vc->vc_num])
1815 speakup_console[vc->vc_num]->tty_stopped = on_off;
1819 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1823 synth_printf("%s %s\n",
1824 label, spk_msg_get(MSG_STATUS_START + on_off));
1825 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1828 static int inc_dec_var(u_char value)
1830 struct st_var_header *p_header;
1831 struct var_t *var_data;
1835 int var_id = (int)value - VAR_START;
1836 int how = (var_id & 1) ? E_INC : E_DEC;
1838 var_id = var_id / 2 + FIRST_SET_VAR;
1839 p_header = spk_get_var_header(var_id);
1842 if (p_header->var_type != VAR_NUM)
1844 var_data = p_header->data;
1845 if (spk_set_num_var(1, p_header, how) != 0)
1847 if (!spk_close_press) {
1848 for (pn = p_header->name; *pn; pn++) {
1855 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1856 var_data->u.n.value);
1857 synth_printf("%s", num_buf);
1861 static void speakup_win_set(struct vc_data *vc)
1865 if (win_start > 1) {
1866 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1869 if (spk_x < win_left || spk_y < win_top) {
1870 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1873 if (win_start && spk_x == win_left && spk_y == win_top) {
1875 win_right = vc->vc_cols - 1;
1877 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1887 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1889 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1890 (int)spk_y + 1, (int)spk_x + 1);
1892 synth_printf("%s\n", info);
1896 static void speakup_win_clear(struct vc_data *vc)
1903 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1906 static void speakup_win_enable(struct vc_data *vc)
1908 if (win_start < 2) {
1909 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1914 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1916 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1919 static void speakup_bits(struct vc_data *vc)
1921 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1923 if (spk_special_handler || val < 1 || val > 6) {
1924 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1927 pb_edit = &spk_punc_info[val];
1928 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1929 spk_special_handler = edit_bits;
1932 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1934 static u_char goto_buf[8];
1940 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1942 if (type == KT_LATIN && ch == '\n')
1950 wch = goto_buf[--num];
1951 goto_buf[num] = '\0';
1952 spkup_write(&wch, 1);
1955 if (ch < '+' || ch > 'y')
1958 goto_buf[num++] = ch;
1959 goto_buf[num] = '\0';
1960 spkup_write(&wch, 1);
1961 maxlen = (*goto_buf >= '0') ? 3 : 4;
1962 if ((ch == '+' || ch == '-') && num == 1)
1964 if (ch >= '0' && ch <= '9' && num < maxlen)
1966 if (num < maxlen - 1 || num > maxlen)
1968 if (ch < 'x' || ch > 'y') {
1971 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1972 goto_buf[num = 0] = '\0';
1973 spk_special_handler = NULL;
1977 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1980 if (*goto_buf < '0')
1982 else if (goto_pos > 0)
1985 if (goto_pos >= vc->vc_cols)
1986 goto_pos = vc->vc_cols - 1;
1989 if (*goto_buf < '0')
1991 else if (goto_pos > 0)
1994 if (goto_pos >= vc->vc_rows)
1995 goto_pos = vc->vc_rows - 1;
1998 goto_buf[num = 0] = '\0';
2000 spk_special_handler = NULL;
2003 spk_pos -= spk_x * 2;
2005 spk_pos += goto_pos * 2;
2009 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2015 static void speakup_goto(struct vc_data *vc)
2017 if (spk_special_handler) {
2018 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2021 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2022 spk_special_handler = handle_goto;
2025 static void speakup_help(struct vc_data *vc)
2027 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2030 static void do_nothing(struct vc_data *vc)
2032 return; /* flush done in do_spkup */
2035 static u_char key_speakup, spk_key_locked;
2037 static void speakup_lock(struct vc_data *vc)
2039 if (!spk_key_locked) {
2040 spk_key_locked = 16;
2048 typedef void (*spkup_hand) (struct vc_data *);
2049 static spkup_hand spkup_handler[] = {
2050 /* must be ordered same as defines in speakup.h */
2051 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2052 speakup_cut, speakup_paste, say_first_char, say_last_char,
2053 say_char, say_prev_char, say_next_char,
2054 say_word, say_prev_word, say_next_word,
2055 say_line, say_prev_line, say_next_line,
2056 top_edge, bottom_edge, left_edge, right_edge,
2057 spell_word, spell_word, say_screen,
2058 say_position, say_attributes,
2059 speakup_off, speakup_parked, say_line, /* this is for indent */
2060 say_from_top, say_to_bottom,
2061 say_from_left, say_to_right,
2062 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2063 speakup_bits, speakup_bits, speakup_bits,
2064 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2065 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2068 static void do_spkup(struct vc_data *vc, u_char value)
2070 if (spk_killed && value != SPEECH_KILL)
2074 spk_shut_up &= 0xfe;
2075 this_speakup_key = value;
2076 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2078 (*spkup_handler[value]) (vc);
2080 if (inc_dec_var(value) < 0)
2085 static const char *pad_chars = "0123456789+-*/\015,.?()";
2088 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2091 unsigned long flags;
2094 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2095 u_char shift_info, offset;
2101 spin_lock_irqsave(&speakup_info.spinlock, flags);
2105 if (type == KT_PAD &&
2106 (vt_get_leds(fg_console, VC_NUMLOCK))) {
2111 value = spk_lastkey = pad_chars[value];
2116 if (keycode >= MAX_KEY)
2118 key_info = spk_our_keys[keycode];
2121 /* Check valid read all mode keys */
2122 if ((cursor_track == read_all_mode) && (!up_flag)) {
2136 shift_info = (shift_state & 0x0f) + key_speakup;
2137 offset = spk_shift_table[shift_info];
2139 new_key = key_info[offset];
2142 if (new_key == SPK_KEY) {
2143 if (!spk_key_locked)
2144 key_speakup = (up_flag) ? 0 : 16;
2145 if (up_flag || spk_killed)
2147 spk_shut_up &= 0xfe;
2153 if (last_keycode == keycode &&
2154 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2155 spk_close_press = 1;
2156 offset = spk_shift_table[shift_info + 32];
2158 if (offset && key_info[offset])
2159 new_key = key_info[offset];
2161 last_keycode = keycode;
2162 last_spk_jiffy = jiffies;
2168 if (type == KT_SPKUP && !spk_special_handler) {
2169 do_spkup(vc, new_key);
2170 spk_close_press = 0;
2174 if (up_flag || spk_killed || type == KT_SHIFT)
2176 spk_shut_up &= 0xfe;
2177 kh = (value == KVAL(K_DOWN)) ||
2178 (value == KVAL(K_UP)) ||
2179 (value == KVAL(K_LEFT)) ||
2180 (value == KVAL(K_RIGHT));
2181 if ((cursor_track != read_all_mode) || !kh)
2184 if (spk_special_handler) {
2185 if (type == KT_SPEC && value == 1) {
2188 } else if (type == KT_LETTER) {
2190 } else if (value == 0x7f) {
2191 value = 8; /* make del = backspace */
2193 ret = (*spk_special_handler) (vc, type, value, keycode);
2194 spk_close_press = 0;
2201 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2205 static int keyboard_notifier_call(struct notifier_block *nb,
2206 unsigned long code, void *_param)
2208 struct keyboard_notifier_param *param = _param;
2209 struct vc_data *vc = param->vc;
2210 int up = !param->down;
2211 int ret = NOTIFY_OK;
2212 static int keycode; /* to hold the current keycode */
2214 if (vc->vc_mode == KD_GRAPHICS)
2218 * First, determine whether we are handling a fake keypress on
2219 * the current processor. If we are, then return NOTIFY_OK,
2220 * to pass the keystroke up the chain. This prevents us from
2221 * trying to take the Speakup lock while it is held by the
2222 * processor on which the simulated keystroke was generated.
2223 * Also, the simulated keystrokes should be ignored by Speakup.
2226 if (speakup_fake_key_pressed())
2231 /* speakup requires keycode and keysym currently */
2232 keycode = param->value;
2234 case KBD_UNBOUND_KEYCODE:
2241 if (speakup_key(vc, param->shift, keycode, param->value, up))
2243 else if (KTYP(param->value) == KT_CUR)
2244 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2246 case KBD_POST_KEYSYM:{
2247 unsigned char type = KTYP(param->value) - 0xf0;
2248 unsigned char val = KVAL(param->value);
2252 do_handle_shift(vc, val, up);
2256 do_handle_latin(vc, val, up);
2259 do_handle_cursor(vc, val, up);
2262 do_handle_spec(vc, val, up);
2271 static int vt_notifier_call(struct notifier_block *nb,
2272 unsigned long code, void *_param)
2274 struct vt_notifier_param *param = _param;
2275 struct vc_data *vc = param->vc;
2279 if (vc->vc_mode == KD_TEXT)
2280 speakup_allocate(vc, GFP_ATOMIC);
2283 speakup_deallocate(vc);
2286 if (param->c == '\b') {
2290 speakup_con_write(vc, &d, 1);
2294 speakup_con_update(vc);
2300 /* called by: module_exit() */
2301 static void __exit speakup_exit(void)
2305 unregister_keyboard_notifier(&keyboard_notifier_block);
2306 unregister_vt_notifier(&vt_notifier_block);
2307 speakup_unregister_devsynth();
2308 speakup_cancel_paste();
2309 del_timer_sync(&cursor_timer);
2310 kthread_stop(speakup_task);
2311 speakup_task = NULL;
2312 mutex_lock(&spk_mutex);
2314 mutex_unlock(&spk_mutex);
2316 speakup_kobj_exit();
2318 for (i = 0; i < MAX_NR_CONSOLES; i++)
2319 kfree(speakup_console[i]);
2321 speakup_remove_virtual_keyboard();
2323 for (i = 0; i < MAXVARS; i++)
2324 speakup_unregister_var(i);
2326 for (i = 0; i < 256; i++) {
2327 if (spk_characters[i] != spk_default_chars[i])
2328 kfree(spk_characters[i]);
2331 spk_free_user_msgs();
2334 /* call by: module_init() */
2335 static int __init speakup_init(void)
2339 struct vc_data *vc = vc_cons[fg_console].d;
2342 /* These first few initializations cannot fail. */
2343 spk_initialize_msgs(); /* Initialize arrays for i18n. */
2344 spk_reset_default_chars();
2345 spk_reset_default_chartab();
2346 spk_strlwr(synth_name);
2347 spk_vars[0].u.n.high = vc->vc_cols;
2348 for (var = spk_vars; var->var_id != MAXVARS; var++)
2349 speakup_register_var(var);
2350 for (var = synth_time_vars;
2351 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2352 speakup_register_var(var);
2353 for (i = 1; spk_punc_info[i].mask != 0; i++)
2354 spk_set_mask_bits(NULL, i, 2);
2356 spk_set_key_info(spk_key_defaults, spk_key_buf);
2358 /* From here on out, initializations can fail. */
2359 err = speakup_add_virtual_keyboard();
2361 goto error_virtkeyboard;
2363 for (i = 0; i < MAX_NR_CONSOLES; i++)
2365 err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2367 goto error_kobjects;
2371 spk_shut_up |= 0x01;
2373 err = speakup_kobj_init();
2375 goto error_kobjects;
2377 synth_init(synth_name);
2378 speakup_register_devsynth();
2380 * register_devsynth might fail, but this error is not fatal.
2381 * /dev/synth is an extra feature; the rest of Speakup
2382 * will work fine without it.
2385 err = register_keyboard_notifier(&keyboard_notifier_block);
2387 goto error_kbdnotifier;
2388 err = register_vt_notifier(&vt_notifier_block);
2390 goto error_vtnotifier;
2392 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2394 if (IS_ERR(speakup_task)) {
2395 err = PTR_ERR(speakup_task);
2399 set_user_nice(speakup_task, 10);
2400 wake_up_process(speakup_task);
2402 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2403 pr_info("synth name on entry is: %s\n", synth_name);
2407 unregister_vt_notifier(&vt_notifier_block);
2410 unregister_keyboard_notifier(&keyboard_notifier_block);
2411 del_timer(&cursor_timer);
2414 speakup_unregister_devsynth();
2415 mutex_lock(&spk_mutex);
2417 mutex_unlock(&spk_mutex);
2418 speakup_kobj_exit();
2421 for (i = 0; i < MAX_NR_CONSOLES; i++)
2422 kfree(speakup_console[i]);
2424 speakup_remove_virtual_keyboard();
2427 for (i = 0; i < MAXVARS; i++)
2428 speakup_unregister_var(i);
2430 for (i = 0; i < 256; i++) {
2431 if (spk_characters[i] != spk_default_chars[i])
2432 kfree(spk_characters[i]);
2435 spk_free_user_msgs();
2441 module_init(speakup_init);
2442 module_exit(speakup_exit);