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