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