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