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