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