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