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;
68int spk_cur_phonetic;
69char spk_str_caps_start[MAXVARLEN + 1] = "\0";
70char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
71char spk_str_pause[MAXVARLEN + 1] = "\0";
72bool spk_paused;
73const 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
85static char mark_cut_flag;
86#define MAX_KEY 160
87static u_char *spk_shift_table;
88u_char *spk_our_keys[MAX_KEY];
89u_char spk_key_buf[600];
90const 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 */
95enum 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 */
105static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
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	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 */
404enum edge {
405	edge_none = 0,
406	edge_top,
407	edge_bottom,
408	edge_left,
409	edge_right,
410	edge_quiet
411};
412
413static 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
422static 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
457static 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
480static 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
495static 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
511static 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
523static 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
544static 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 < sizeof(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
591static 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
604static 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
659static 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
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
1272enum 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
1280static 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
1298static 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
1307void 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
1321void spk_reset_default_chartab(void)
1322{
1323	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1324}
1325
1326static const struct st_bits_data *pb_edit;
1327
1328static 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 */
1350static 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
1368static 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
1377enum 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
1388static u_char is_cursor;
1389static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1390static int cursor_con;
1391
1392static void reset_highlight_buffers(struct vc_data *);
1393
1394static enum read_all_command read_all_key;
1395
1396static int in_keyboard_notifier;
1397
1398static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1399
1400static 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
1407static 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
1429static 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
1437static 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
1448static 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
1520static 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
1542static 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
1573static 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
1604static 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
1613static 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
1643static 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
1665static 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
1690static 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;
1733out:
1734	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1735}
1736
1737/* called by: vt_notifier_call() */
1738static 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() */
1762static 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
1791static 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
1808static 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
1846static 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
1879static 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
1914static 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
1924static 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
1937static 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
1950static 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') {
1988oops:
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';
2019do_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
2035static 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
2045static void speakup_help(struct vc_data *vc)
2046{
2047	spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2048}
2049
2050static void do_nothing(struct vc_data *vc)
2051{
2052	return;			/* flush done in do_spkup */
2053}
2054
2055static u_char key_speakup, spk_key_locked;
2056
2057static 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
2068typedef void (*spkup_hand) (struct vc_data *);
2069static 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
2088static 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
2105static const char *pad_chars = "0123456789+-*/\015,.?()";
2106
2107static int
2108speakup_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	}
2188no_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;
2221out:
2222	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2223	return ret;
2224}
2225
2226static 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	}
2291out:
2292	in_keyboard_notifier = 0;
2293	return ret;
2294}
2295
2296static 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() */
2327static 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() */
2363static 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
2435error_task:
2436	unregister_vt_notifier(&vt_notifier_block);
2437
2438error_vtnotifier:
2439	unregister_keyboard_notifier(&keyboard_notifier_block);
2440	del_timer(&cursor_timer);
2441
2442error_kbdnotifier:
2443	speakup_unregister_devsynth();
2444	mutex_lock(&spk_mutex);
2445	synth_release();
2446	mutex_unlock(&spk_mutex);
2447	speakup_kobj_exit();
2448
2449error_kobjects:
2450	for (i = 0; i < MAX_NR_CONSOLES; i++)
2451		kfree(speakup_console[i]);
2452
2453	speakup_remove_virtual_keyboard();
2454
2455error_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
2466out:
2467	return err;
2468}
2469
2470module_param_named(bell_pos, spk_vars[BELL_POS_ID].u.n.default_val, int, 0444);
2471module_param_named(spell_delay, spk_vars[SPELL_DELAY_ID].u.n.default_val, int, 0444);
2472module_param_named(attrib_bleep, spk_vars[ATTRIB_BLEEP_ID].u.n.default_val, int, 0444);
2473module_param_named(bleeps, spk_vars[BLEEPS_ID].u.n.default_val, int, 0444);
2474module_param_named(bleep_time, spk_vars[BLEEP_TIME_ID].u.n.default_val, int, 0444);
2475module_param_named(punc_level, spk_vars[PUNC_LEVEL_ID].u.n.default_val, int, 0444);
2476module_param_named(reading_punc, spk_vars[READING_PUNC_ID].u.n.default_val, int, 0444);
2477module_param_named(cursor_time, spk_vars[CURSOR_TIME_ID].u.n.default_val, int, 0444);
2478module_param_named(say_control, spk_vars[SAY_CONTROL_ID].u.n.default_val, int, 0444);
2479module_param_named(say_word_ctl, spk_vars[SAY_WORD_CTL_ID].u.n.default_val, int, 0444);
2480module_param_named(no_interrupt, spk_vars[NO_INTERRUPT_ID].u.n.default_val, int, 0444);
2481module_param_named(key_echo, spk_vars[KEY_ECHO_ID].u.n.default_val, int, 0444);
2482module_param_named(cur_phonetic, spk_vars[CUR_PHONETIC_ID].u.n.default_val, int, 0444);
2483
2484MODULE_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.");
2485MODULE_PARM_DESC(spell_delay, "This controls how fast a word is spelled when speakup's spell word review command is pressed.");
2486MODULE_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.");
2487MODULE_PARM_DESC(bleeps, "This controls whether one hears beeps through the PC speaker when using speakup review commands.");
2488MODULE_PARM_DESC(bleep_time, "This controls the duration of the PC speaker beeps speakup produces.");
2489MODULE_PARM_DESC(punc_level, "Controls the level of punctuation spoken as the screen is displayed, not reviewed.");
2490MODULE_PARM_DESC(reading_punc, "It controls the level of punctuation when reviewing the screen with speakup's screen review commands.");
2491MODULE_PARM_DESC(cursor_time, "This controls cursor delay when using arrow keys.");
2492MODULE_PARM_DESC(say_control, "This controls if speakup speaks shift, alt and control when those keys are pressed or not.");
2493MODULE_PARM_DESC(say_word_ctl, "Sets the say_word_ctl on load.");
2494MODULE_PARM_DESC(no_interrupt, "Controls if typing interrupts output from speakup.");
2495MODULE_PARM_DESC(key_echo, "Controls if speakup speaks keys when they are typed. One = on zero = off or don't echo keys.");
2496MODULE_PARM_DESC(cur_phonetic, "Controls if speakup speaks letters phonetically during navigation. One = on zero = off or don't speak phonetically.");
2497
2498module_init(speakup_init);
2499module_exit(speakup_exit);
2500