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