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