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