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