xref: /linux/drivers/accessibility/speakup/main.c (revision e292ead0c9dad3580cfd45693a59902c8d31a0a7)
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 int spk_cur_phonetic;
69 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
70 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
71 char spk_str_pause[MAXVARLEN + 1] = "\0";
72 bool spk_paused;
73 const struct st_bits_data spk_punc_info[] = {
74 	{"none", "", 0},
75 	{"some", "/$%&@", SOME},
76 	{"most", "$%&#()=+*/@^<>|\\", MOST},
77 	{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
78 	{"delimiters", "", B_WDLM},
79 	{"repeats", "()", CH_RPT},
80 	{"extended numeric", "", B_EXNUM},
81 	{"symbols", "", B_SYM},
82 	{NULL, NULL}
83 };
84 
85 static char mark_cut_flag;
86 #define MAX_KEY 160
87 static u_char *spk_shift_table;
88 u_char *spk_our_keys[MAX_KEY];
89 u_char spk_key_buf[600];
90 const u_char spk_key_defaults[] = {
91 #include "speakupmap.h"
92 };
93 
94 /* cursor track modes, must be ordered same as cursor_msgs in enum msg_index_t */
95 enum cursor_track {
96 	CT_Off = 0,
97 	CT_On,
98 	CT_Highlight,
99 	CT_Window,
100 	CT_Max,
101 	read_all_mode = CT_Max,
102 };
103 
104 /* Speakup Cursor Track Variables */
105 static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
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 	synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
394 	if (bg > 7) {
395 		synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
396 		bg -= 8;
397 	} else {
398 		synth_printf(" %s ", spk_msg_get(MSG_ON));
399 	}
400 	synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
401 }
402 
403 /* must be ordered same as edge_msgs in enum msg_index_t */
404 enum edge {
405 	edge_none = 0,
406 	edge_top,
407 	edge_bottom,
408 	edge_left,
409 	edge_right,
410 	edge_quiet
411 };
412 
announce_edge(struct vc_data * vc,enum edge msg_id)413 static void announce_edge(struct vc_data *vc, enum edge msg_id)
414 {
415 	if (spk_bleeps & 1)
416 		bleep(spk_y);
417 	if ((spk_bleeps & 2) && (msg_id < edge_quiet))
418 		synth_printf("%s\n",
419 			     spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
420 }
421 
speak_char(u16 ch)422 static void speak_char(u16 ch)
423 {
424 	char *cp;
425 	struct var_t *direct = spk_get_var(DIRECT);
426 
427 	if (ch >= 0x100 || (direct && direct->u.n.value)) {
428 		if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
429 			spk_pitch_shift++;
430 			synth_printf("%s", spk_str_caps_start);
431 		}
432 		synth_putwc_s(ch);
433 		if (ch < 0x100 && IS_CHAR(ch, B_CAP))
434 			synth_printf("%s", spk_str_caps_stop);
435 		return;
436 	}
437 
438 	cp = spk_characters[ch];
439 	if (!cp) {
440 		pr_info("%s: cp == NULL!\n", __func__);
441 		return;
442 	}
443 	if (IS_CHAR(ch, B_CAP)) {
444 		spk_pitch_shift++;
445 		synth_printf("%s %s %s",
446 			     spk_str_caps_start, cp, spk_str_caps_stop);
447 	} else {
448 		if (*cp == '^') {
449 			cp++;
450 			synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
451 		} else {
452 			synth_printf(" %s ", cp);
453 		}
454 	}
455 }
456 
get_char(struct vc_data * vc,u16 * pos,u_char * attribs)457 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
458 {
459 	u16 ch = ' ';
460 
461 	if (vc && pos) {
462 		u16 w;
463 		u16 c;
464 
465 		pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
466 		w = scr_readw(pos);
467 		c = w & 0xff;
468 
469 		if (w & vc->vc_hi_font_mask) {
470 			w &= ~vc->vc_hi_font_mask;
471 			c |= 0x100;
472 		}
473 
474 		ch = inverse_translate(vc, c, true);
475 		*attribs = (w & 0xff00) >> 8;
476 	}
477 	return ch;
478 }
479 
say_char(struct vc_data * vc)480 static void say_char(struct vc_data *vc)
481 {
482 	u16 ch;
483 
484 	spk_old_attr = spk_attr;
485 	ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
486 	if (spk_attr != spk_old_attr) {
487 		if (spk_attrib_bleep & 1)
488 			bleep(spk_y);
489 		if (spk_attrib_bleep & 2)
490 			say_attributes(vc);
491 	}
492 	speak_char(ch);
493 }
494 
say_phonetic_char(struct vc_data * vc)495 static void say_phonetic_char(struct vc_data *vc)
496 {
497 	u16 ch;
498 
499 	spk_old_attr = spk_attr;
500 	ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
501 	if (ch <= 0x7f && isalpha(ch)) {
502 		ch &= 0x1f;
503 		synth_printf("%s\n", phonetic[--ch]);
504 	} else {
505 		if (ch < 0x100 && IS_CHAR(ch, B_NUM))
506 			synth_printf("%s ", spk_msg_get(MSG_NUMBER));
507 		speak_char(ch);
508 	}
509 }
510 
say_prev_char(struct vc_data * vc)511 static void say_prev_char(struct vc_data *vc)
512 {
513 	spk_parked |= 0x01;
514 	if (spk_x == 0) {
515 		announce_edge(vc, edge_left);
516 		return;
517 	}
518 	spk_x--;
519 	spk_pos -= 2;
520 	say_char(vc);
521 }
522 
say_next_char(struct vc_data * vc)523 static void say_next_char(struct vc_data *vc)
524 {
525 	spk_parked |= 0x01;
526 	if (spk_x == vc->vc_cols - 1) {
527 		announce_edge(vc, edge_right);
528 		return;
529 	}
530 	spk_x++;
531 	spk_pos += 2;
532 	say_char(vc);
533 }
534 
535 /* get_word - will first check to see if the character under the
536  * reading cursor is a space and if spk_say_word_ctl is true it will
537  * return the word space.  If spk_say_word_ctl is not set it will check to
538  * see if there is a word starting on the next position to the right
539  * and return that word if it exists.  If it does not exist it will
540  * move left to the beginning of any previous word on the line or the
541  * beginning off the line whichever comes first..
542  */
543 
get_word(struct vc_data * vc)544 static u_long get_word(struct vc_data *vc)
545 {
546 	u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
547 	u16 ch;
548 	u16 attr_ch;
549 	u_char temp;
550 
551 	spk_old_attr = spk_attr;
552 	ch = get_char(vc, (u_short *)tmp_pos, &temp);
553 
554 /* decided to take out the sayword if on a space (mis-information */
555 	if (spk_say_word_ctl && ch == SPACE) {
556 		*buf = '\0';
557 		synth_printf("%s\n", spk_msg_get(MSG_SPACE));
558 		return 0;
559 	} else if (tmpx < vc->vc_cols - 2 &&
560 		   (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
561 		   get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
562 		tmp_pos += 2;
563 		tmpx++;
564 	} else {
565 		while (tmpx > 0) {
566 			ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
567 			if ((ch == SPACE || ch == 0 ||
568 			     (ch < 0x100 && IS_WDLM(ch))) &&
569 			    get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
570 				break;
571 			tmp_pos -= 2;
572 			tmpx--;
573 		}
574 	}
575 	attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
576 	buf[cnt++] = attr_ch;
577 	while (tmpx < vc->vc_cols - 1 && cnt < ARRAY_SIZE(buf) - 1) {
578 		tmp_pos += 2;
579 		tmpx++;
580 		ch = get_char(vc, (u_short *)tmp_pos, &temp);
581 		if (ch == SPACE || ch == 0 ||
582 		    (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
583 		     ch > SPACE))
584 			break;
585 		buf[cnt++] = ch;
586 	}
587 	buf[cnt] = '\0';
588 	return cnt;
589 }
590 
say_word(struct vc_data * vc)591 static void say_word(struct vc_data *vc)
592 {
593 	u_long cnt = get_word(vc);
594 	u_short saved_punc_mask = spk_punc_mask;
595 
596 	if (cnt == 0)
597 		return;
598 	spk_punc_mask = PUNC;
599 	buf[cnt++] = SPACE;
600 	spkup_write(buf, cnt);
601 	spk_punc_mask = saved_punc_mask;
602 }
603 
say_prev_word(struct vc_data * vc)604 static void say_prev_word(struct vc_data *vc)
605 {
606 	u_char temp;
607 	u16 ch;
608 	enum edge edge_said = edge_none;
609 	u_short last_state = 0, state = 0;
610 
611 	spk_parked |= 0x01;
612 
613 	if (spk_x == 0) {
614 		if (spk_y == 0) {
615 			announce_edge(vc, edge_top);
616 			return;
617 		}
618 		spk_y--;
619 		spk_x = vc->vc_cols;
620 		edge_said = edge_quiet;
621 	}
622 	while (1) {
623 		if (spk_x == 0) {
624 			if (spk_y == 0) {
625 				edge_said = edge_top;
626 				break;
627 			}
628 			if (edge_said != edge_quiet)
629 				edge_said = edge_left;
630 			if (state > 0)
631 				break;
632 			spk_y--;
633 			spk_x = vc->vc_cols - 1;
634 		} else {
635 			spk_x--;
636 		}
637 		spk_pos -= 2;
638 		ch = get_char(vc, (u_short *)spk_pos, &temp);
639 		if (ch == SPACE || ch == 0)
640 			state = 0;
641 		else if (ch < 0x100 && IS_WDLM(ch))
642 			state = 1;
643 		else
644 			state = 2;
645 		if (state < last_state) {
646 			spk_pos += 2;
647 			spk_x++;
648 			break;
649 		}
650 		last_state = state;
651 	}
652 	if (spk_x == 0 && edge_said == edge_quiet)
653 		edge_said = edge_left;
654 	if (edge_said > edge_none && edge_said < edge_quiet)
655 		announce_edge(vc, edge_said);
656 	say_word(vc);
657 }
658 
say_next_word(struct vc_data * vc)659 static void say_next_word(struct vc_data *vc)
660 {
661 	u_char temp;
662 	u16 ch;
663 	enum edge edge_said = edge_none;
664 	u_short 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 > edge_none)
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 enum spk_vars_id {
1273 	BELL_POS_ID = 0, SPELL_DELAY_ID, ATTRIB_BLEEP_ID,
1274 	BLEEPS_ID, BLEEP_TIME_ID, PUNC_LEVEL_ID,
1275 	READING_PUNC_ID, CURSOR_TIME_ID, SAY_CONTROL_ID,
1276 	SAY_WORD_CTL_ID, NO_INTERRUPT_ID, KEY_ECHO_ID,
1277 	CUR_PHONETIC_ID, V_LAST_VAR_ID, NB_ID
1278 };
1279 
1280 static struct var_t spk_vars[NB_ID] = {
1281 	/* bell must be first to set high limit */
1282 	[BELL_POS_ID] = { BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1283 	[SPELL_DELAY_ID] = { SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1284 	[ATTRIB_BLEEP_ID] = { ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1285 	[BLEEPS_ID] = { BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1286 	[BLEEP_TIME_ID] = { BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1287 	[PUNC_LEVEL_ID] = { PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1288 	[READING_PUNC_ID] = { READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1289 	[CURSOR_TIME_ID] = { CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1290 	[SAY_CONTROL_ID] = { SAY_CONTROL, TOGGLE_0},
1291 	[SAY_WORD_CTL_ID] = {SAY_WORD_CTL, TOGGLE_0},
1292 	[NO_INTERRUPT_ID] = { NO_INTERRUPT, TOGGLE_0},
1293 	[KEY_ECHO_ID] = { KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1294 	[CUR_PHONETIC_ID] = { CUR_PHONETIC, .u.n = {NULL, 0, 0, 1, 0, 0, NULL} },
1295 	V_LAST_VAR
1296 };
1297 
toggle_cursoring(struct vc_data * vc)1298 static void toggle_cursoring(struct vc_data *vc)
1299 {
1300 	if (cursor_track == read_all_mode)
1301 		cursor_track = prev_cursor_track;
1302 	if (++cursor_track >= CT_Max)
1303 		cursor_track = 0;
1304 	synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1305 }
1306 
spk_reset_default_chars(void)1307 void spk_reset_default_chars(void)
1308 {
1309 	int i;
1310 
1311 	/* First, free any non-default */
1312 	for (i = 0; i < 256; i++) {
1313 		if (spk_characters[i] &&
1314 		    (spk_characters[i] != spk_default_chars[i]))
1315 			kfree(spk_characters[i]);
1316 	}
1317 
1318 	memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1319 }
1320 
spk_reset_default_chartab(void)1321 void spk_reset_default_chartab(void)
1322 {
1323 	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1324 }
1325 
1326 static const struct st_bits_data *pb_edit;
1327 
edit_bits(struct vc_data * vc,u_char type,u_char ch,u_short key)1328 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1329 {
1330 	short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1331 
1332 	if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1333 		return -1;
1334 	if (ch == SPACE) {
1335 		synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1336 		spk_special_handler = NULL;
1337 		return 1;
1338 	}
1339 	if (mask < PUNC && !(ch_type & PUNC))
1340 		return -1;
1341 	spk_chartab[ch] ^= mask;
1342 	speak_char(ch);
1343 	synth_printf(" %s\n",
1344 		     (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1345 		     spk_msg_get(MSG_OFF));
1346 	return 1;
1347 }
1348 
1349 /* Allocation concurrency is protected by the console semaphore */
speakup_allocate(struct vc_data * vc,gfp_t gfp_flags)1350 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1351 {
1352 	int vc_num;
1353 
1354 	vc_num = vc->vc_num;
1355 	if (!speakup_console[vc_num]) {
1356 		speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1357 						  gfp_flags);
1358 		if (!speakup_console[vc_num])
1359 			return -ENOMEM;
1360 		speakup_date(vc);
1361 	} else if (!spk_parked) {
1362 		speakup_date(vc);
1363 	}
1364 
1365 	return 0;
1366 }
1367 
speakup_deallocate(struct vc_data * vc)1368 static void speakup_deallocate(struct vc_data *vc)
1369 {
1370 	int vc_num;
1371 
1372 	vc_num = vc->vc_num;
1373 	kfree(speakup_console[vc_num]);
1374 	speakup_console[vc_num] = NULL;
1375 }
1376 
1377 enum read_all_command {
1378 	RA_NEXT_SENT = KVAL(K_DOWN)+1,
1379 	RA_PREV_LINE = KVAL(K_LEFT)+1,
1380 	RA_NEXT_LINE = KVAL(K_RIGHT)+1,
1381 	RA_PREV_SENT = KVAL(K_UP)+1,
1382 	RA_DOWN_ARROW,
1383 	RA_TIMER,
1384 	RA_FIND_NEXT_SENT,
1385 	RA_FIND_PREV_SENT,
1386 };
1387 
1388 static u_char is_cursor;
1389 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1390 static int cursor_con;
1391 
1392 static void reset_highlight_buffers(struct vc_data *);
1393 
1394 static enum read_all_command read_all_key;
1395 
1396 static int in_keyboard_notifier;
1397 
1398 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1399 
kbd_fakekey2(struct vc_data * vc,enum read_all_command command)1400 static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
1401 {
1402 	del_timer(&cursor_timer);
1403 	speakup_fake_down_arrow();
1404 	start_read_all_timer(vc, command);
1405 }
1406 
read_all_doc(struct vc_data * vc)1407 static void read_all_doc(struct vc_data *vc)
1408 {
1409 	if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1410 		return;
1411 	if (!synth_supports_indexing())
1412 		return;
1413 	if (cursor_track != read_all_mode)
1414 		prev_cursor_track = cursor_track;
1415 	cursor_track = read_all_mode;
1416 	spk_reset_index_count(0);
1417 	if (get_sentence_buf(vc, 0) == -1) {
1418 		del_timer(&cursor_timer);
1419 		if (!in_keyboard_notifier)
1420 			speakup_fake_down_arrow();
1421 		start_read_all_timer(vc, RA_DOWN_ARROW);
1422 	} else {
1423 		say_sentence_num(0, 0);
1424 		synth_insert_next_index(0);
1425 		start_read_all_timer(vc, RA_TIMER);
1426 	}
1427 }
1428 
stop_read_all(struct vc_data * vc)1429 static void stop_read_all(struct vc_data *vc)
1430 {
1431 	del_timer(&cursor_timer);
1432 	cursor_track = prev_cursor_track;
1433 	spk_shut_up &= 0xfe;
1434 	spk_do_flush();
1435 }
1436 
start_read_all_timer(struct vc_data * vc,enum read_all_command command)1437 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
1438 {
1439 	struct var_t *cursor_timeout;
1440 
1441 	cursor_con = vc->vc_num;
1442 	read_all_key = command;
1443 	cursor_timeout = spk_get_var(CURSOR_TIME);
1444 	mod_timer(&cursor_timer,
1445 		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1446 }
1447 
handle_cursor_read_all(struct vc_data * vc,enum read_all_command command)1448 static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
1449 {
1450 	int indcount, sentcount, rv, sn;
1451 
1452 	switch (command) {
1453 	case RA_NEXT_SENT:
1454 		/* Get Current Sentence */
1455 		spk_get_index_count(&indcount, &sentcount);
1456 		/*printk("%d %d  ", indcount, sentcount); */
1457 		spk_reset_index_count(sentcount + 1);
1458 		if (indcount == 1) {
1459 			if (!say_sentence_num(sentcount + 1, 0)) {
1460 				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1461 				return;
1462 			}
1463 			synth_insert_next_index(0);
1464 		} else {
1465 			sn = 0;
1466 			if (!say_sentence_num(sentcount + 1, 1)) {
1467 				sn = 1;
1468 				spk_reset_index_count(sn);
1469 			} else {
1470 				synth_insert_next_index(0);
1471 			}
1472 			if (!say_sentence_num(sn, 0)) {
1473 				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1474 				return;
1475 			}
1476 			synth_insert_next_index(0);
1477 		}
1478 		start_read_all_timer(vc, RA_TIMER);
1479 		break;
1480 	case RA_PREV_SENT:
1481 		break;
1482 	case RA_NEXT_LINE:
1483 		read_all_doc(vc);
1484 		break;
1485 	case RA_PREV_LINE:
1486 		break;
1487 	case RA_DOWN_ARROW:
1488 		if (get_sentence_buf(vc, 0) == -1) {
1489 			kbd_fakekey2(vc, RA_DOWN_ARROW);
1490 		} else {
1491 			say_sentence_num(0, 0);
1492 			synth_insert_next_index(0);
1493 			start_read_all_timer(vc, RA_TIMER);
1494 		}
1495 		break;
1496 	case RA_FIND_NEXT_SENT:
1497 		rv = get_sentence_buf(vc, 0);
1498 		if (rv == -1)
1499 			read_all_doc(vc);
1500 		if (rv == 0) {
1501 			kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1502 		} else {
1503 			say_sentence_num(1, 0);
1504 			synth_insert_next_index(0);
1505 			start_read_all_timer(vc, RA_TIMER);
1506 		}
1507 		break;
1508 	case RA_FIND_PREV_SENT:
1509 		break;
1510 	case RA_TIMER:
1511 		spk_get_index_count(&indcount, &sentcount);
1512 		if (indcount < 2)
1513 			kbd_fakekey2(vc, RA_DOWN_ARROW);
1514 		else
1515 			start_read_all_timer(vc, RA_TIMER);
1516 		break;
1517 	}
1518 }
1519 
pre_handle_cursor(struct vc_data * vc,u_char value,char up_flag)1520 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1521 {
1522 	unsigned long flags;
1523 
1524 	spin_lock_irqsave(&speakup_info.spinlock, flags);
1525 	if (cursor_track == read_all_mode) {
1526 		spk_parked &= 0xfe;
1527 		if (!synth || up_flag || spk_shut_up) {
1528 			spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1529 			return NOTIFY_STOP;
1530 		}
1531 		del_timer(&cursor_timer);
1532 		spk_shut_up &= 0xfe;
1533 		spk_do_flush();
1534 		start_read_all_timer(vc, value + 1);
1535 		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1536 		return NOTIFY_STOP;
1537 	}
1538 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1539 	return NOTIFY_OK;
1540 }
1541 
do_handle_cursor(struct vc_data * vc,u_char value,char up_flag)1542 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1543 {
1544 	unsigned long flags;
1545 	struct var_t *cursor_timeout;
1546 
1547 	spin_lock_irqsave(&speakup_info.spinlock, flags);
1548 	spk_parked &= 0xfe;
1549 	if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1550 		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1551 		return;
1552 	}
1553 	spk_shut_up &= 0xfe;
1554 	if (spk_no_intr)
1555 		spk_do_flush();
1556 /* the key press flushes if !no_inter but we want to flush on cursor
1557  * moves regardless of no_inter state
1558  */
1559 	is_cursor = value + 1;
1560 	old_cursor_pos = vc->vc_pos;
1561 	old_cursor_x = vc->state.x;
1562 	old_cursor_y = vc->state.y;
1563 	speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1564 	cursor_con = vc->vc_num;
1565 	if (cursor_track == CT_Highlight)
1566 		reset_highlight_buffers(vc);
1567 	cursor_timeout = spk_get_var(CURSOR_TIME);
1568 	mod_timer(&cursor_timer,
1569 		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1570 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1571 }
1572 
update_color_buffer(struct vc_data * vc,const u16 * ic,int len)1573 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1574 {
1575 	int i, bi, hi;
1576 	int vc_num = vc->vc_num;
1577 
1578 	bi = (vc->vc_attr & 0x70) >> 4;
1579 	hi = speakup_console[vc_num]->ht.highsize[bi];
1580 
1581 	i = 0;
1582 	if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1583 		speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1584 		speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1585 		speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1586 	}
1587 	while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1588 		if (ic[i] > 32) {
1589 			speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1590 			hi++;
1591 		} else if ((ic[i] == 32) && (hi != 0)) {
1592 			if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1593 			    32) {
1594 				speakup_console[vc_num]->ht.highbuf[bi][hi] =
1595 				    ic[i];
1596 				hi++;
1597 			}
1598 		}
1599 		i++;
1600 	}
1601 	speakup_console[vc_num]->ht.highsize[bi] = hi;
1602 }
1603 
reset_highlight_buffers(struct vc_data * vc)1604 static void reset_highlight_buffers(struct vc_data *vc)
1605 {
1606 	int i;
1607 	int vc_num = vc->vc_num;
1608 
1609 	for (i = 0; i < 8; i++)
1610 		speakup_console[vc_num]->ht.highsize[i] = 0;
1611 }
1612 
count_highlight_color(struct vc_data * vc)1613 static int count_highlight_color(struct vc_data *vc)
1614 {
1615 	int i, bg;
1616 	int cc;
1617 	int vc_num = vc->vc_num;
1618 	u16 ch;
1619 	u16 *start = (u16 *)vc->vc_origin;
1620 
1621 	for (i = 0; i < 8; i++)
1622 		speakup_console[vc_num]->ht.bgcount[i] = 0;
1623 
1624 	for (i = 0; i < vc->vc_rows; i++) {
1625 		u16 *end = start + vc->vc_cols * 2;
1626 		u16 *ptr;
1627 
1628 		for (ptr = start; ptr < end; ptr++) {
1629 			ch = get_attributes(vc, ptr);
1630 			bg = (ch & 0x70) >> 4;
1631 			speakup_console[vc_num]->ht.bgcount[bg]++;
1632 		}
1633 		start += vc->vc_size_row;
1634 	}
1635 
1636 	cc = 0;
1637 	for (i = 0; i < 8; i++)
1638 		if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1639 			cc++;
1640 	return cc;
1641 }
1642 
get_highlight_color(struct vc_data * vc)1643 static int get_highlight_color(struct vc_data *vc)
1644 {
1645 	int i, j;
1646 	unsigned int cptr[8];
1647 	int vc_num = vc->vc_num;
1648 
1649 	for (i = 0; i < 8; i++)
1650 		cptr[i] = i;
1651 
1652 	for (i = 0; i < 7; i++)
1653 		for (j = i + 1; j < 8; j++)
1654 			if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1655 			    speakup_console[vc_num]->ht.bgcount[cptr[j]])
1656 				swap(cptr[i], cptr[j]);
1657 
1658 	for (i = 0; i < 8; i++)
1659 		if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1660 			if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1661 				return cptr[i];
1662 	return -1;
1663 }
1664 
speak_highlight(struct vc_data * vc)1665 static int speak_highlight(struct vc_data *vc)
1666 {
1667 	int hc, d;
1668 	int vc_num = vc->vc_num;
1669 
1670 	if (count_highlight_color(vc) == 1)
1671 		return 0;
1672 	hc = get_highlight_color(vc);
1673 	if (hc != -1) {
1674 		d = vc->state.y - speakup_console[vc_num]->ht.cy;
1675 		if ((d == 1) || (d == -1))
1676 			if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1677 				return 0;
1678 		spk_parked |= 0x01;
1679 		spk_do_flush();
1680 		spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1681 			    speakup_console[vc_num]->ht.highsize[hc]);
1682 		spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1683 		spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1684 		spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1685 		return 1;
1686 	}
1687 	return 0;
1688 }
1689 
cursor_done(struct timer_list * unused)1690 static void cursor_done(struct timer_list *unused)
1691 {
1692 	struct vc_data *vc = vc_cons[cursor_con].d;
1693 	unsigned long flags;
1694 
1695 	del_timer(&cursor_timer);
1696 	spin_lock_irqsave(&speakup_info.spinlock, flags);
1697 	if (cursor_con != fg_console) {
1698 		is_cursor = 0;
1699 		goto out;
1700 	}
1701 	speakup_date(vc);
1702 	if (win_enabled) {
1703 		if (vc->state.x >= win_left && vc->state.x <= win_right &&
1704 		    vc->state.y >= win_top && vc->state.y <= win_bottom) {
1705 			spk_keydown = 0;
1706 			is_cursor = 0;
1707 			goto out;
1708 		}
1709 	}
1710 	if (cursor_track == read_all_mode) {
1711 		handle_cursor_read_all(vc, read_all_key);
1712 		goto out;
1713 	}
1714 	if (cursor_track == CT_Highlight) {
1715 		if (speak_highlight(vc)) {
1716 			spk_keydown = 0;
1717 			is_cursor = 0;
1718 			goto out;
1719 		}
1720 	}
1721 	if (cursor_track == CT_Window)
1722 		speakup_win_say(vc);
1723 	else if (is_cursor == 1 || is_cursor == 4)
1724 		say_line_from_to(vc, 0, vc->vc_cols, 0);
1725 	else {
1726 		if (spk_cur_phonetic == 1)
1727 			say_phonetic_char(vc);
1728 		else
1729 			say_char(vc);
1730 	}
1731 	spk_keydown = 0;
1732 	is_cursor = 0;
1733 out:
1734 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1735 }
1736 
1737 /* called by: vt_notifier_call() */
speakup_bs(struct vc_data * vc)1738 static void speakup_bs(struct vc_data *vc)
1739 {
1740 	unsigned long flags;
1741 
1742 	if (!speakup_console[vc->vc_num])
1743 		return;
1744 	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1745 		/* Speakup output, discard */
1746 		return;
1747 	if (!spk_parked)
1748 		speakup_date(vc);
1749 	if (spk_shut_up || !synth) {
1750 		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1751 		return;
1752 	}
1753 	if (vc->vc_num == fg_console && spk_keydown) {
1754 		spk_keydown = 0;
1755 		if (!is_cursor)
1756 			say_char(vc);
1757 	}
1758 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1759 }
1760 
1761 /* called by: vt_notifier_call() */
speakup_con_write(struct vc_data * vc,u16 * str,int len)1762 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1763 {
1764 	unsigned long flags;
1765 
1766 	if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1767 		return;
1768 	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1769 		/* Speakup output, discard */
1770 		return;
1771 	if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1772 		bleep(3);
1773 	if ((is_cursor) || (cursor_track == read_all_mode)) {
1774 		if (cursor_track == CT_Highlight)
1775 			update_color_buffer(vc, str, len);
1776 		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1777 		return;
1778 	}
1779 	if (win_enabled) {
1780 		if (vc->state.x >= win_left && vc->state.x <= win_right &&
1781 		    vc->state.y >= win_top && vc->state.y <= win_bottom) {
1782 			spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1783 			return;
1784 		}
1785 	}
1786 
1787 	spkup_write(str, len);
1788 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1789 }
1790 
speakup_con_update(struct vc_data * vc)1791 static void speakup_con_update(struct vc_data *vc)
1792 {
1793 	unsigned long flags;
1794 
1795 	if (!speakup_console[vc->vc_num] || spk_parked || !synth)
1796 		return;
1797 	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1798 		/* Speakup output, discard */
1799 		return;
1800 	speakup_date(vc);
1801 	if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1802 		synth_printf("%s", spk_str_pause);
1803 		spk_paused = true;
1804 	}
1805 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1806 }
1807 
do_handle_spec(struct vc_data * vc,u_char value,char up_flag)1808 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1809 {
1810 	unsigned long flags;
1811 	int on_off = 2;
1812 	char *label;
1813 
1814 	if (!synth || up_flag || spk_killed)
1815 		return;
1816 	spin_lock_irqsave(&speakup_info.spinlock, flags);
1817 	spk_shut_up &= 0xfe;
1818 	if (spk_no_intr)
1819 		spk_do_flush();
1820 	switch (value) {
1821 	case KVAL(K_CAPS):
1822 		label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1823 		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1824 		break;
1825 	case KVAL(K_NUM):
1826 		label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1827 		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1828 		break;
1829 	case KVAL(K_HOLD):
1830 		label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1831 		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1832 		if (speakup_console[vc->vc_num])
1833 			speakup_console[vc->vc_num]->tty_stopped = on_off;
1834 		break;
1835 	default:
1836 		spk_parked &= 0xfe;
1837 		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1838 		return;
1839 	}
1840 	if (on_off < 2)
1841 		synth_printf("%s %s\n",
1842 			     label, spk_msg_get(MSG_STATUS_START + on_off));
1843 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1844 }
1845 
inc_dec_var(u_char value)1846 static int inc_dec_var(u_char value)
1847 {
1848 	struct st_var_header *p_header;
1849 	struct var_t *var_data;
1850 	char num_buf[32];
1851 	char *cp = num_buf;
1852 	char *pn;
1853 	int var_id = (int)value - VAR_START;
1854 	int how = (var_id & 1) ? E_INC : E_DEC;
1855 
1856 	var_id = var_id / 2 + FIRST_SET_VAR;
1857 	p_header = spk_get_var_header(var_id);
1858 	if (!p_header)
1859 		return -1;
1860 	if (p_header->var_type != VAR_NUM)
1861 		return -1;
1862 	var_data = p_header->data;
1863 	if (spk_set_num_var(1, p_header, how) != 0)
1864 		return -1;
1865 	if (!spk_close_press) {
1866 		for (pn = p_header->name; *pn; pn++) {
1867 			if (*pn == '_')
1868 				*cp = SPACE;
1869 			else
1870 				*cp++ = *pn;
1871 		}
1872 	}
1873 	snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1874 		 var_data->u.n.value);
1875 	synth_printf("%s", num_buf);
1876 	return 0;
1877 }
1878 
speakup_win_set(struct vc_data * vc)1879 static void speakup_win_set(struct vc_data *vc)
1880 {
1881 	char info[40];
1882 
1883 	if (win_start > 1) {
1884 		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1885 		return;
1886 	}
1887 	if (spk_x < win_left || spk_y < win_top) {
1888 		synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1889 		return;
1890 	}
1891 	if (win_start && spk_x == win_left && spk_y == win_top) {
1892 		win_left = 0;
1893 		win_right = vc->vc_cols - 1;
1894 		win_bottom = spk_y;
1895 		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1896 			 (int)win_top + 1);
1897 	} else {
1898 		if (!win_start) {
1899 			win_top = spk_y;
1900 			win_left = spk_x;
1901 		} else {
1902 			win_bottom = spk_y;
1903 			win_right = spk_x;
1904 		}
1905 		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1906 			 (win_start) ?
1907 				spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1908 			 (int)spk_y + 1, (int)spk_x + 1);
1909 	}
1910 	synth_printf("%s\n", info);
1911 	win_start++;
1912 }
1913 
speakup_win_clear(struct vc_data * vc)1914 static void speakup_win_clear(struct vc_data *vc)
1915 {
1916 	win_top = 0;
1917 	win_bottom = 0;
1918 	win_left = 0;
1919 	win_right = 0;
1920 	win_start = 0;
1921 	synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1922 }
1923 
speakup_win_enable(struct vc_data * vc)1924 static void speakup_win_enable(struct vc_data *vc)
1925 {
1926 	if (win_start < 2) {
1927 		synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1928 		return;
1929 	}
1930 	win_enabled ^= 1;
1931 	if (win_enabled)
1932 		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1933 	else
1934 		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1935 }
1936 
speakup_bits(struct vc_data * vc)1937 static void speakup_bits(struct vc_data *vc)
1938 {
1939 	int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1940 
1941 	if (spk_special_handler || val < 1 || val > 6) {
1942 		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1943 		return;
1944 	}
1945 	pb_edit = &spk_punc_info[val];
1946 	synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1947 	spk_special_handler = edit_bits;
1948 }
1949 
handle_goto(struct vc_data * vc,u_char type,u_char ch,u_short key)1950 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1951 {
1952 	static u_char goto_buf[8];
1953 	static int num;
1954 	int maxlen;
1955 	char *cp;
1956 	u16 wch;
1957 
1958 	if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1959 		goto do_goto;
1960 	if (type == KT_LATIN && ch == '\n')
1961 		goto do_goto;
1962 	if (type != 0)
1963 		goto oops;
1964 	if (ch == 8) {
1965 		u16 wch;
1966 
1967 		if (num == 0)
1968 			return -1;
1969 		wch = goto_buf[--num];
1970 		goto_buf[num] = '\0';
1971 		spkup_write(&wch, 1);
1972 		return 1;
1973 	}
1974 	if (ch < '+' || ch > 'y')
1975 		goto oops;
1976 	wch = ch;
1977 	goto_buf[num++] = ch;
1978 	goto_buf[num] = '\0';
1979 	spkup_write(&wch, 1);
1980 	maxlen = (*goto_buf >= '0') ? 3 : 4;
1981 	if ((ch == '+' || ch == '-') && num == 1)
1982 		return 1;
1983 	if (ch >= '0' && ch <= '9' && num < maxlen)
1984 		return 1;
1985 	if (num < maxlen - 1 || num > maxlen)
1986 		goto oops;
1987 	if (ch < 'x' || ch > 'y') {
1988 oops:
1989 		if (!spk_killed)
1990 			synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1991 		goto_buf[num = 0] = '\0';
1992 		spk_special_handler = NULL;
1993 		return 1;
1994 	}
1995 
1996 	/* Do not replace with kstrtoul: here we need cp to be updated */
1997 	goto_pos = simple_strtoul(goto_buf, &cp, 10);
1998 
1999 	if (*cp == 'x') {
2000 		if (*goto_buf < '0')
2001 			goto_pos += spk_x;
2002 		else if (goto_pos > 0)
2003 			goto_pos--;
2004 
2005 		if (goto_pos >= vc->vc_cols)
2006 			goto_pos = vc->vc_cols - 1;
2007 		goto_x = 1;
2008 	} else {
2009 		if (*goto_buf < '0')
2010 			goto_pos += spk_y;
2011 		else if (goto_pos > 0)
2012 			goto_pos--;
2013 
2014 		if (goto_pos >= vc->vc_rows)
2015 			goto_pos = vc->vc_rows - 1;
2016 		goto_x = 0;
2017 	}
2018 	goto_buf[num = 0] = '\0';
2019 do_goto:
2020 	spk_special_handler = NULL;
2021 	spk_parked |= 0x01;
2022 	if (goto_x) {
2023 		spk_pos -= spk_x * 2;
2024 		spk_x = goto_pos;
2025 		spk_pos += goto_pos * 2;
2026 		say_word(vc);
2027 	} else {
2028 		spk_y = goto_pos;
2029 		spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2030 		say_line(vc);
2031 	}
2032 	return 1;
2033 }
2034 
speakup_goto(struct vc_data * vc)2035 static void speakup_goto(struct vc_data *vc)
2036 {
2037 	if (spk_special_handler) {
2038 		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2039 		return;
2040 	}
2041 	synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2042 	spk_special_handler = handle_goto;
2043 }
2044 
speakup_help(struct vc_data * vc)2045 static void speakup_help(struct vc_data *vc)
2046 {
2047 	spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2048 }
2049 
do_nothing(struct vc_data * vc)2050 static void do_nothing(struct vc_data *vc)
2051 {
2052 	return;			/* flush done in do_spkup */
2053 }
2054 
2055 static u_char key_speakup, spk_key_locked;
2056 
speakup_lock(struct vc_data * vc)2057 static void speakup_lock(struct vc_data *vc)
2058 {
2059 	if (!spk_key_locked) {
2060 		spk_key_locked = 16;
2061 		key_speakup = 16;
2062 	} else {
2063 		spk_key_locked = 0;
2064 		key_speakup = 0;
2065 	}
2066 }
2067 
2068 typedef void (*spkup_hand) (struct vc_data *);
2069 static spkup_hand spkup_handler[] = {
2070 	/* must be ordered same as defines in speakup.h */
2071 	do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2072 	speakup_cut, speakup_paste, say_first_char, say_last_char,
2073 	say_char, say_prev_char, say_next_char,
2074 	say_word, say_prev_word, say_next_word,
2075 	say_line, say_prev_line, say_next_line,
2076 	top_edge, bottom_edge, left_edge, right_edge,
2077 	spell_word, spell_word, say_screen,
2078 	say_position, say_attributes,
2079 	speakup_off, speakup_parked, say_line,	/* this is for indent */
2080 	say_from_top, say_to_bottom,
2081 	say_from_left, say_to_right,
2082 	say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2083 	speakup_bits, speakup_bits, speakup_bits,
2084 	speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2085 	speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2086 };
2087 
do_spkup(struct vc_data * vc,u_char value)2088 static void do_spkup(struct vc_data *vc, u_char value)
2089 {
2090 	if (spk_killed && value != SPEECH_KILL)
2091 		return;
2092 	spk_keydown = 0;
2093 	spk_lastkey = 0;
2094 	spk_shut_up &= 0xfe;
2095 	this_speakup_key = value;
2096 	if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2097 		spk_do_flush();
2098 		(*spkup_handler[value]) (vc);
2099 	} else {
2100 		if (inc_dec_var(value) < 0)
2101 			bleep(9);
2102 	}
2103 }
2104 
2105 static const char *pad_chars = "0123456789+-*/\015,.?()";
2106 
2107 static int
speakup_key(struct vc_data * vc,int shift_state,int keycode,u_short keysym,int up_flag)2108 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2109 	    int up_flag)
2110 {
2111 	unsigned long flags;
2112 	int kh;
2113 	u_char *key_info;
2114 	u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2115 	u_char shift_info, offset;
2116 	int ret = 0;
2117 
2118 	if (!synth)
2119 		return 0;
2120 
2121 	spin_lock_irqsave(&speakup_info.spinlock, flags);
2122 	tty = vc->port.tty;
2123 	if (type >= 0xf0)
2124 		type -= 0xf0;
2125 	if (type == KT_PAD &&
2126 	    (vt_get_leds(fg_console, VC_NUMLOCK))) {
2127 		if (up_flag) {
2128 			spk_keydown = 0;
2129 			goto out;
2130 		}
2131 		value = pad_chars[value];
2132 		spk_lastkey = value;
2133 		spk_keydown++;
2134 		spk_parked &= 0xfe;
2135 		goto no_map;
2136 	}
2137 	if (keycode >= MAX_KEY)
2138 		goto no_map;
2139 	key_info = spk_our_keys[keycode];
2140 	if (!key_info)
2141 		goto no_map;
2142 	/* Check valid read all mode keys */
2143 	if ((cursor_track == read_all_mode) && (!up_flag)) {
2144 		switch (value) {
2145 		case KVAL(K_DOWN):
2146 		case KVAL(K_UP):
2147 		case KVAL(K_LEFT):
2148 		case KVAL(K_RIGHT):
2149 		case KVAL(K_PGUP):
2150 		case KVAL(K_PGDN):
2151 			break;
2152 		default:
2153 			stop_read_all(vc);
2154 			break;
2155 		}
2156 	}
2157 	shift_info = (shift_state & 0x0f) + key_speakup;
2158 	offset = spk_shift_table[shift_info];
2159 	if (offset) {
2160 		new_key = key_info[offset];
2161 		if (new_key) {
2162 			ret = 1;
2163 			if (new_key == SPK_KEY) {
2164 				if (!spk_key_locked)
2165 					key_speakup = (up_flag) ? 0 : 16;
2166 				if (up_flag || spk_killed)
2167 					goto out;
2168 				spk_shut_up &= 0xfe;
2169 				spk_do_flush();
2170 				goto out;
2171 			}
2172 			if (up_flag)
2173 				goto out;
2174 			if (last_keycode == keycode &&
2175 			    time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2176 				spk_close_press = 1;
2177 				offset = spk_shift_table[shift_info + 32];
2178 				/* double press? */
2179 				if (offset && key_info[offset])
2180 					new_key = key_info[offset];
2181 			}
2182 			last_keycode = keycode;
2183 			last_spk_jiffy = jiffies;
2184 			type = KT_SPKUP;
2185 			value = new_key;
2186 		}
2187 	}
2188 no_map:
2189 	if (type == KT_SPKUP && !spk_special_handler) {
2190 		do_spkup(vc, new_key);
2191 		spk_close_press = 0;
2192 		ret = 1;
2193 		goto out;
2194 	}
2195 	if (up_flag || spk_killed || type == KT_SHIFT)
2196 		goto out;
2197 	spk_shut_up &= 0xfe;
2198 	kh = (value == KVAL(K_DOWN)) ||
2199 	    (value == KVAL(K_UP)) ||
2200 	    (value == KVAL(K_LEFT)) ||
2201 	    (value == KVAL(K_RIGHT));
2202 	if ((cursor_track != read_all_mode) || !kh)
2203 		if (!spk_no_intr)
2204 			spk_do_flush();
2205 	if (spk_special_handler) {
2206 		if (type == KT_SPEC && value == 1) {
2207 			value = '\n';
2208 			type = KT_LATIN;
2209 		} else if (type == KT_LETTER) {
2210 			type = KT_LATIN;
2211 		} else if (value == 0x7f) {
2212 			value = 8;	/* make del = backspace */
2213 		}
2214 		ret = (*spk_special_handler) (vc, type, value, keycode);
2215 		spk_close_press = 0;
2216 		if (ret < 0)
2217 			bleep(9);
2218 		goto out;
2219 	}
2220 	last_keycode = 0;
2221 out:
2222 	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2223 	return ret;
2224 }
2225 
keyboard_notifier_call(struct notifier_block * nb,unsigned long code,void * _param)2226 static int keyboard_notifier_call(struct notifier_block *nb,
2227 				  unsigned long code, void *_param)
2228 {
2229 	struct keyboard_notifier_param *param = _param;
2230 	struct vc_data *vc = param->vc;
2231 	int up = !param->down;
2232 	int ret = NOTIFY_OK;
2233 	static int keycode;	/* to hold the current keycode */
2234 
2235 	in_keyboard_notifier = 1;
2236 
2237 	if (vc->vc_mode == KD_GRAPHICS)
2238 		goto out;
2239 
2240 	/*
2241 	 * First, determine whether we are handling a fake keypress on
2242 	 * the current processor.  If we are, then return NOTIFY_OK,
2243 	 * to pass the keystroke up the chain.  This prevents us from
2244 	 * trying to take the Speakup lock while it is held by the
2245 	 * processor on which the simulated keystroke was generated.
2246 	 * Also, the simulated keystrokes should be ignored by Speakup.
2247 	 */
2248 
2249 	if (speakup_fake_key_pressed())
2250 		goto out;
2251 
2252 	switch (code) {
2253 	case KBD_KEYCODE:
2254 		/* speakup requires keycode and keysym currently */
2255 		keycode = param->value;
2256 		break;
2257 	case KBD_UNBOUND_KEYCODE:
2258 		/* not used yet */
2259 		break;
2260 	case KBD_UNICODE:
2261 		/* not used yet */
2262 		break;
2263 	case KBD_KEYSYM:
2264 		if (speakup_key(vc, param->shift, keycode, param->value, up))
2265 			ret = NOTIFY_STOP;
2266 		else if (KTYP(param->value) == KT_CUR)
2267 			ret = pre_handle_cursor(vc, KVAL(param->value), up);
2268 		break;
2269 	case KBD_POST_KEYSYM:{
2270 			unsigned char type = KTYP(param->value) - 0xf0;
2271 			unsigned char val = KVAL(param->value);
2272 
2273 			switch (type) {
2274 			case KT_SHIFT:
2275 				do_handle_shift(vc, val, up);
2276 				break;
2277 			case KT_LATIN:
2278 			case KT_LETTER:
2279 				do_handle_latin(vc, val, up);
2280 				break;
2281 			case KT_CUR:
2282 				do_handle_cursor(vc, val, up);
2283 				break;
2284 			case KT_SPEC:
2285 				do_handle_spec(vc, val, up);
2286 				break;
2287 			}
2288 			break;
2289 		}
2290 	}
2291 out:
2292 	in_keyboard_notifier = 0;
2293 	return ret;
2294 }
2295 
vt_notifier_call(struct notifier_block * nb,unsigned long code,void * _param)2296 static int vt_notifier_call(struct notifier_block *nb,
2297 			    unsigned long code, void *_param)
2298 {
2299 	struct vt_notifier_param *param = _param;
2300 	struct vc_data *vc = param->vc;
2301 
2302 	switch (code) {
2303 	case VT_ALLOCATE:
2304 		if (vc->vc_mode == KD_TEXT)
2305 			speakup_allocate(vc, GFP_ATOMIC);
2306 		break;
2307 	case VT_DEALLOCATE:
2308 		speakup_deallocate(vc);
2309 		break;
2310 	case VT_WRITE:
2311 		if (param->c == '\b') {
2312 			speakup_bs(vc);
2313 		} else {
2314 			u16 d = param->c;
2315 
2316 			speakup_con_write(vc, &d, 1);
2317 		}
2318 		break;
2319 	case VT_UPDATE:
2320 		speakup_con_update(vc);
2321 		break;
2322 	}
2323 	return NOTIFY_OK;
2324 }
2325 
2326 /* called by: module_exit() */
speakup_exit(void)2327 static void __exit speakup_exit(void)
2328 {
2329 	int i;
2330 
2331 	unregister_keyboard_notifier(&keyboard_notifier_block);
2332 	unregister_vt_notifier(&vt_notifier_block);
2333 	speakup_unregister_devsynth();
2334 	speakup_cancel_selection();
2335 	speakup_cancel_paste();
2336 	del_timer_sync(&cursor_timer);
2337 	kthread_stop(speakup_task);
2338 	speakup_task = NULL;
2339 	mutex_lock(&spk_mutex);
2340 	synth_release();
2341 	mutex_unlock(&spk_mutex);
2342 	spk_ttyio_unregister_ldisc();
2343 
2344 	speakup_kobj_exit();
2345 
2346 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2347 		kfree(speakup_console[i]);
2348 
2349 	speakup_remove_virtual_keyboard();
2350 
2351 	for (i = 0; i < MAXVARS; i++)
2352 		speakup_unregister_var(i);
2353 
2354 	for (i = 0; i < 256; i++) {
2355 		if (spk_characters[i] != spk_default_chars[i])
2356 			kfree(spk_characters[i]);
2357 	}
2358 
2359 	spk_free_user_msgs();
2360 }
2361 
2362 /* call by: module_init() */
speakup_init(void)2363 static int __init speakup_init(void)
2364 {
2365 	int i;
2366 	long err = 0;
2367 	struct vc_data *vc = vc_cons[fg_console].d;
2368 	struct var_t *var;
2369 
2370 	/* These first few initializations cannot fail. */
2371 	spk_initialize_msgs();	/* Initialize arrays for i18n. */
2372 	spk_reset_default_chars();
2373 	spk_reset_default_chartab();
2374 	spk_strlwr(synth_name);
2375 	spk_vars[0].u.n.high = vc->vc_cols;
2376 	for (var = spk_vars; var->var_id != MAXVARS; var++)
2377 		speakup_register_var(var);
2378 	for (var = synth_time_vars;
2379 	     (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2380 		speakup_register_var(var);
2381 	for (i = 1; spk_punc_info[i].mask != 0; i++)
2382 		spk_set_mask_bits(NULL, i, 2);
2383 
2384 	spk_set_key_info(spk_key_defaults, spk_key_buf);
2385 
2386 	/* From here on out, initializations can fail. */
2387 	err = speakup_add_virtual_keyboard();
2388 	if (err)
2389 		goto error_virtkeyboard;
2390 
2391 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2392 		if (vc_cons[i].d) {
2393 			err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2394 			if (err)
2395 				goto error_kobjects;
2396 		}
2397 
2398 	if (spk_quiet_boot)
2399 		spk_shut_up |= 0x01;
2400 
2401 	err = speakup_kobj_init();
2402 	if (err)
2403 		goto error_kobjects;
2404 
2405 	spk_ttyio_register_ldisc();
2406 	synth_init(synth_name);
2407 	speakup_register_devsynth();
2408 	/*
2409 	 * register_devsynth might fail, but this error is not fatal.
2410 	 * /dev/synth is an extra feature; the rest of Speakup
2411 	 * will work fine without it.
2412 	 */
2413 
2414 	err = register_keyboard_notifier(&keyboard_notifier_block);
2415 	if (err)
2416 		goto error_kbdnotifier;
2417 	err = register_vt_notifier(&vt_notifier_block);
2418 	if (err)
2419 		goto error_vtnotifier;
2420 
2421 	speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2422 
2423 	if (IS_ERR(speakup_task)) {
2424 		err = PTR_ERR(speakup_task);
2425 		goto error_task;
2426 	}
2427 
2428 	set_user_nice(speakup_task, 10);
2429 	wake_up_process(speakup_task);
2430 
2431 	pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2432 	pr_info("synth name on entry is: %s\n", synth_name);
2433 	goto out;
2434 
2435 error_task:
2436 	unregister_vt_notifier(&vt_notifier_block);
2437 
2438 error_vtnotifier:
2439 	unregister_keyboard_notifier(&keyboard_notifier_block);
2440 	del_timer(&cursor_timer);
2441 
2442 error_kbdnotifier:
2443 	speakup_unregister_devsynth();
2444 	mutex_lock(&spk_mutex);
2445 	synth_release();
2446 	mutex_unlock(&spk_mutex);
2447 	speakup_kobj_exit();
2448 
2449 error_kobjects:
2450 	for (i = 0; i < MAX_NR_CONSOLES; i++)
2451 		kfree(speakup_console[i]);
2452 
2453 	speakup_remove_virtual_keyboard();
2454 
2455 error_virtkeyboard:
2456 	for (i = 0; i < MAXVARS; i++)
2457 		speakup_unregister_var(i);
2458 
2459 	for (i = 0; i < 256; i++) {
2460 		if (spk_characters[i] != spk_default_chars[i])
2461 			kfree(spk_characters[i]);
2462 	}
2463 
2464 	spk_free_user_msgs();
2465 
2466 out:
2467 	return err;
2468 }
2469 
2470 module_param_named(bell_pos, spk_vars[BELL_POS_ID].u.n.default_val, int, 0444);
2471 module_param_named(spell_delay, spk_vars[SPELL_DELAY_ID].u.n.default_val, int, 0444);
2472 module_param_named(attrib_bleep, spk_vars[ATTRIB_BLEEP_ID].u.n.default_val, int, 0444);
2473 module_param_named(bleeps, spk_vars[BLEEPS_ID].u.n.default_val, int, 0444);
2474 module_param_named(bleep_time, spk_vars[BLEEP_TIME_ID].u.n.default_val, int, 0444);
2475 module_param_named(punc_level, spk_vars[PUNC_LEVEL_ID].u.n.default_val, int, 0444);
2476 module_param_named(reading_punc, spk_vars[READING_PUNC_ID].u.n.default_val, int, 0444);
2477 module_param_named(cursor_time, spk_vars[CURSOR_TIME_ID].u.n.default_val, int, 0444);
2478 module_param_named(say_control, spk_vars[SAY_CONTROL_ID].u.n.default_val, int, 0444);
2479 module_param_named(say_word_ctl, spk_vars[SAY_WORD_CTL_ID].u.n.default_val, int, 0444);
2480 module_param_named(no_interrupt, spk_vars[NO_INTERRUPT_ID].u.n.default_val, int, 0444);
2481 module_param_named(key_echo, spk_vars[KEY_ECHO_ID].u.n.default_val, int, 0444);
2482 module_param_named(cur_phonetic, spk_vars[CUR_PHONETIC_ID].u.n.default_val, int, 0444);
2483 
2484 MODULE_PARM_DESC(bell_pos, "This works much like a typewriter bell. If for example 72 is echoed to bell_pos, it will beep the PC speaker when typing on a line past character 72.");
2485 MODULE_PARM_DESC(spell_delay, "This controls how fast a word is spelled when speakup's spell word review command is pressed.");
2486 MODULE_PARM_DESC(attrib_bleep, "Beeps the PC speaker when there is an attribute change such as background color when using speakup review commands. One = on, zero = off.");
2487 MODULE_PARM_DESC(bleeps, "This controls whether one hears beeps through the PC speaker when using speakup review commands.");
2488 MODULE_PARM_DESC(bleep_time, "This controls the duration of the PC speaker beeps speakup produces.");
2489 MODULE_PARM_DESC(punc_level, "Controls the level of punctuation spoken as the screen is displayed, not reviewed.");
2490 MODULE_PARM_DESC(reading_punc, "It controls the level of punctuation when reviewing the screen with speakup's screen review commands.");
2491 MODULE_PARM_DESC(cursor_time, "This controls cursor delay when using arrow keys.");
2492 MODULE_PARM_DESC(say_control, "This controls if speakup speaks shift, alt and control when those keys are pressed or not.");
2493 MODULE_PARM_DESC(say_word_ctl, "Sets the say_word_ctl on load.");
2494 MODULE_PARM_DESC(no_interrupt, "Controls if typing interrupts output from speakup.");
2495 MODULE_PARM_DESC(key_echo, "Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys.");
2496 MODULE_PARM_DESC(cur_phonetic, "Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically.");
2497 
2498 module_init(speakup_init);
2499 module_exit(speakup_exit);
2500