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