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