main.c revision ca2beaf84d9678c12b17d92623f0e90829d6ca13
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#include <linux/bootmem.h>	/* for alloc_bootmem */
41
42/* speakup_*_selection */
43#include <linux/module.h>
44#include <linux/sched.h>
45#include <linux/slab.h>
46#include <linux/types.h>
47#include <linux/consolemap.h>
48
49#include <linux/spinlock.h>
50#include <linux/notifier.h>
51
52#include <linux/uaccess.h>	/* copy_from|to|user() and others */
53
54#include "spk_priv.h"
55#include "speakup.h"
56
57#define MAX_DELAY msecs_to_jiffies(500)
58#define MINECHOCHAR SPACE
59
60MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
61MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
62MODULE_DESCRIPTION("Speakup console speech");
63MODULE_LICENSE("GPL");
64MODULE_VERSION(SPEAKUP_VERSION);
65
66char *synth_name;
67module_param_named(synth, synth_name, charp, S_IRUGO);
68module_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
69
70MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
71MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
72
73special_func spk_special_handler;
74
75short spk_pitch_shift, synth_flags;
76static char buf[256];
77int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
78int spk_no_intr, spk_spell_delay;
79int spk_key_echo, spk_say_word_ctl;
80int spk_say_ctrl, spk_bell_pos;
81short spk_punc_mask;
82int spk_punc_level, spk_reading_punc;
83char spk_str_caps_start[MAXVARLEN + 1] = "\0", spk_str_caps_stop[MAXVARLEN + 1] = "\0";
84const struct st_bits_data spk_punc_info[] = {
85	{"none", "", 0},
86	{"some", "/$%&@", SOME},
87	{"most", "$%&#()=+*/@^<>|\\", MOST},
88	{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
89	{"delimiters", "", B_WDLM},
90	{"repeats", "()", CH_RPT},
91	{"extended numeric", "", B_EXNUM},
92	{"symbols", "", B_SYM},
93	{0, 0}
94};
95
96static char mark_cut_flag;
97#define MAX_KEY 160
98u_char *spk_our_keys[MAX_KEY], *spk_shift_table;
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
254struct 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
261struct 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	freq = vals[val % 12];
287	if (val > 11)
288		freq *= (1 << (val / 12));
289	spk_unprocessed_sound.freq = freq;
290	spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
291	spk_unprocessed_sound.active = 1;
292	/* We can only have 1 active sound at a time. */
293}
294
295static void speakup_shut_up(struct vc_data *vc)
296{
297	if (spk_killed)
298		return;
299	spk_shut_up |= 0x01;
300	spk_parked &= 0xfe;
301	speakup_date(vc);
302	if (synth != NULL)
303		spk_do_flush();
304}
305
306static void speech_kill(struct vc_data *vc)
307{
308	char val = synth->is_alive(synth);
309	if (val == 0)
310		return;
311
312	/* re-enables synth, if disabled */
313	if (val == 2 || spk_killed) {
314		/* dead */
315		spk_shut_up &= ~0x40;
316		synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
317	} else {
318		synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
319		spk_shut_up |= 0x40;
320	}
321}
322
323static void speakup_off(struct vc_data *vc)
324{
325	if (spk_shut_up & 0x80) {
326		spk_shut_up &= 0x7f;
327		synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
328	} else {
329		spk_shut_up |= 0x80;
330		synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
331	}
332	speakup_date(vc);
333}
334
335static void speakup_parked(struct vc_data *vc)
336{
337	if (spk_parked & 0x80) {
338		spk_parked = 0;
339		synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
340	} else {
341		spk_parked |= 0x80;
342		synth_printf("%s\n", spk_msg_get(MSG_PARKED));
343	}
344}
345
346static void speakup_cut(struct vc_data *vc)
347{
348	static const char err_buf[] = "set selection failed";
349	int ret;
350
351	if (!mark_cut_flag) {
352		mark_cut_flag = 1;
353		spk_xs = (u_short) spk_x;
354		spk_ys = (u_short) spk_y;
355		spk_sel_cons = vc;
356		synth_printf("%s\n", spk_msg_get(MSG_MARK));
357		return;
358	}
359	spk_xe = (u_short) spk_x;
360	spk_ye = (u_short) spk_y;
361	mark_cut_flag = 0;
362	synth_printf("%s\n", spk_msg_get(MSG_CUT));
363
364	speakup_clear_selection();
365	ret = speakup_set_selection(tty);
366
367	switch (ret) {
368	case 0:
369		break;		/* no error */
370	case -EFAULT:
371		pr_warn("%sEFAULT\n", err_buf);
372		break;
373	case -EINVAL:
374		pr_warn("%sEINVAL\n", err_buf);
375		break;
376	case -ENOMEM:
377		pr_warn("%sENOMEM\n", err_buf);
378		break;
379	}
380}
381
382static void speakup_paste(struct vc_data *vc)
383{
384	if (mark_cut_flag) {
385		mark_cut_flag = 0;
386		synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
387	} else {
388		synth_printf("%s\n", spk_msg_get(MSG_PASTE));
389		speakup_paste_selection(tty);
390	}
391}
392
393static void say_attributes(struct vc_data *vc)
394{
395	int fg = spk_attr & 0x0f;
396	int bg = spk_attr >> 4;
397	if (fg > 8) {
398		synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
399		fg -= 8;
400	}
401	synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
402	if (bg > 7) {
403		synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
404		bg -= 8;
405	} else
406		synth_printf(" %s ", spk_msg_get(MSG_ON));
407	synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
408}
409
410enum {
411	edge_top = 1,
412	edge_bottom,
413	edge_left,
414	edge_right,
415	edge_quiet
416};
417
418static void announce_edge(struct vc_data *vc, int msg_id)
419{
420	if (spk_bleeps & 1)
421		bleep(spk_y);
422	if ((spk_bleeps & 2) && (msg_id < edge_quiet))
423		synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
424}
425
426static void speak_char(u_char ch)
427{
428	char *cp = spk_characters[ch];
429	struct var_t *direct = spk_get_var(DIRECT);
430	if (direct && direct->u.n.value) {
431		if (IS_CHAR(ch, B_CAP)) {
432			spk_pitch_shift++;
433			synth_printf("%s", spk_str_caps_start);
434		}
435		synth_printf("%c", ch);
436		if (IS_CHAR(ch, B_CAP))
437			synth_printf("%s", spk_str_caps_stop);
438		return;
439	}
440	if (cp == NULL) {
441		pr_info("speak_char: cp == NULL!\n");
442		return;
443	}
444	synth_buffer_add(SPACE);
445	if (IS_CHAR(ch, B_CAP)) {
446		spk_pitch_shift++;
447		synth_printf("%s", spk_str_caps_start);
448		synth_printf("%s", cp);
449		synth_printf("%s", spk_str_caps_stop);
450	} else {
451		if (*cp == '^') {
452			synth_printf("%s", spk_msg_get(MSG_CTRL));
453			cp++;
454		}
455		synth_printf("%s", cp);
456	}
457	synth_buffer_add(SPACE);
458}
459
460static u16 get_char(struct vc_data *vc, u16 * pos, u_char * attribs)
461{
462	u16 ch = ' ';
463	if (vc && pos) {
464		u16 w = scr_readw(pos);
465		u16 c = w & 0xff;
466
467		if (w & vc->vc_hi_font_mask)
468			c |= 0x100;
469
470		ch = inverse_translate(vc, c, 0);
471		*attribs = (w & 0xff00) >> 8;
472	}
473	return ch;
474}
475
476static void say_char(struct vc_data *vc)
477{
478	u_short ch;
479	spk_old_attr = spk_attr;
480	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
481	if (spk_attr != spk_old_attr) {
482		if (spk_attrib_bleep & 1)
483			bleep(spk_y);
484		if (spk_attrib_bleep & 2)
485			say_attributes(vc);
486	}
487	speak_char(ch & 0xff);
488}
489
490static void say_phonetic_char(struct vc_data *vc)
491{
492	u_short ch;
493	spk_old_attr = spk_attr;
494	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
495	if (isascii(ch) && isalpha(ch)) {
496		ch &= 0x1f;
497		synth_printf("%s\n", phonetic[--ch]);
498	} else {
499		if (IS_CHAR(ch, B_NUM))
500			synth_printf("%s ", spk_msg_get(MSG_NUMBER));
501		speak_char(ch);
502	}
503}
504
505static void say_prev_char(struct vc_data *vc)
506{
507	spk_parked |= 0x01;
508	if (spk_x == 0) {
509		announce_edge(vc, edge_left);
510		return;
511	}
512	spk_x--;
513	spk_pos -= 2;
514	say_char(vc);
515}
516
517static void say_next_char(struct vc_data *vc)
518{
519	spk_parked |= 0x01;
520	if (spk_x == vc->vc_cols - 1) {
521		announce_edge(vc, edge_right);
522		return;
523	}
524	spk_x++;
525	spk_pos += 2;
526	say_char(vc);
527}
528
529/* get_word - will first check to see if the character under the
530 * reading cursor is a space and if spk_say_word_ctl is true it will
531 * return the word space.  If spk_say_word_ctl is not set it will check to
532 * see if there is a word starting on the next position to the right
533 * and return that word if it exists.  If it does not exist it will
534 * move left to the beginning of any previous word on the line or the
535 * beginning off the line whichever comes first.. */
536
537static u_long get_word(struct vc_data *vc)
538{
539	u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
540	char ch;
541	u_short attr_ch;
542	u_char temp;
543	spk_old_attr = spk_attr;
544	ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
545
546/* decided to take out the sayword if on a space (mis-information */
547	if (spk_say_word_ctl && ch == SPACE) {
548		*buf = '\0';
549		synth_printf("%s\n", spk_msg_get(MSG_SPACE));
550		return 0;
551	} else if ((tmpx < vc->vc_cols - 2)
552		   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
553		   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
554		       SPACE)) {
555		tmp_pos += 2;
556		tmpx++;
557	} else
558		while (tmpx > 0) {
559			ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
560			if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
561			    && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
562				SPACE))
563				break;
564			tmp_pos -= 2;
565			tmpx--;
566		}
567	attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
568	buf[cnt++] = attr_ch & 0xff;
569	while (tmpx < vc->vc_cols - 1) {
570		tmp_pos += 2;
571		tmpx++;
572		ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
573		if ((ch == SPACE) || ch == 0
574		    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
575			break;
576		buf[cnt++] = ch;
577	}
578	buf[cnt] = '\0';
579	return cnt;
580}
581
582static void say_word(struct vc_data *vc)
583{
584	u_long cnt = get_word(vc);
585	u_short saved_punc_mask = spk_punc_mask;
586	if (cnt == 0)
587		return;
588	spk_punc_mask = PUNC;
589	buf[cnt++] = SPACE;
590	spkup_write(buf, cnt);
591	spk_punc_mask = saved_punc_mask;
592}
593
594static void say_prev_word(struct vc_data *vc)
595{
596	u_char temp;
597	char ch;
598	u_short edge_said = 0, last_state = 0, state = 0;
599	spk_parked |= 0x01;
600
601	if (spk_x == 0) {
602		if (spk_y == 0) {
603			announce_edge(vc, edge_top);
604			return;
605		}
606		spk_y--;
607		spk_x = vc->vc_cols;
608		edge_said = edge_quiet;
609	}
610	while (1) {
611		if (spk_x == 0) {
612			if (spk_y == 0) {
613				edge_said = edge_top;
614				break;
615			}
616			if (edge_said != edge_quiet)
617				edge_said = edge_left;
618			if (state > 0)
619				break;
620			spk_y--;
621			spk_x = vc->vc_cols - 1;
622		} else
623			spk_x--;
624		spk_pos -= 2;
625		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
626		if (ch == SPACE || ch == 0)
627			state = 0;
628		else if (IS_WDLM(ch))
629			state = 1;
630		else
631			state = 2;
632		if (state < last_state) {
633			spk_pos += 2;
634			spk_x++;
635			break;
636		}
637		last_state = state;
638	}
639	if (spk_x == 0 && edge_said == edge_quiet)
640		edge_said = edge_left;
641	if (edge_said > 0 && edge_said < edge_quiet)
642		announce_edge(vc, edge_said);
643	say_word(vc);
644}
645
646static void say_next_word(struct vc_data *vc)
647{
648	u_char temp;
649	char ch;
650	u_short edge_said = 0, last_state = 2, state = 0;
651	spk_parked |= 0x01;
652
653	if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
654		announce_edge(vc, edge_bottom);
655		return;
656	}
657	while (1) {
658		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
659		if (ch == SPACE || ch == 0)
660			state = 0;
661		else if (IS_WDLM(ch))
662			state = 1;
663		else
664			state = 2;
665		if (state > last_state)
666			break;
667		if (spk_x >= vc->vc_cols - 1) {
668			if (spk_y == vc->vc_rows - 1) {
669				edge_said = edge_bottom;
670				break;
671			}
672			state = 0;
673			spk_y++;
674			spk_x = 0;
675			edge_said = edge_right;
676		} else
677			spk_x++;
678		spk_pos += 2;
679		last_state = state;
680	}
681	if (edge_said > 0)
682		announce_edge(vc, edge_said);
683	say_word(vc);
684}
685
686static void spell_word(struct vc_data *vc)
687{
688	static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
689	char *cp = buf, *str_cap = spk_str_caps_stop;
690	char *cp1, *last_cap = spk_str_caps_stop;
691	u_char ch;
692	if (!get_word(vc))
693		return;
694	while ((ch = (u_char) *cp)) {
695		if (cp != buf)
696			synth_printf(" %s ", delay_str[spk_spell_delay]);
697		if (IS_CHAR(ch, B_CAP)) {
698			str_cap = spk_str_caps_start;
699			if (*spk_str_caps_stop)
700				spk_pitch_shift++;
701			else	/* synth has no pitch */
702				last_cap = spk_str_caps_stop;
703		} else
704			str_cap = spk_str_caps_stop;
705		if (str_cap != last_cap) {
706			synth_printf("%s", str_cap);
707			last_cap = str_cap;
708		}
709		if (this_speakup_key == SPELL_PHONETIC
710		    && (isascii(ch) && isalpha(ch))) {
711			ch &= 31;
712			cp1 = phonetic[--ch];
713		} else {
714			cp1 = spk_characters[ch];
715			if (*cp1 == '^') {
716				synth_printf("%s", spk_msg_get(MSG_CTRL));
717				cp1++;
718			}
719		}
720		synth_printf("%s", cp1);
721		cp++;
722	}
723	if (str_cap != spk_str_caps_stop)
724		synth_printf("%s", spk_str_caps_stop);
725}
726
727static int get_line(struct vc_data *vc)
728{
729	u_long tmp = spk_pos - (spk_x * 2);
730	int i = 0;
731	u_char tmp2;
732
733	spk_old_attr = spk_attr;
734	spk_attr = get_attributes((u_short *) spk_pos);
735	for (i = 0; i < vc->vc_cols; i++) {
736		buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
737		tmp += 2;
738	}
739	for (--i; i >= 0; i--)
740		if (buf[i] != SPACE)
741			break;
742	return ++i;
743}
744
745static void say_line(struct vc_data *vc)
746{
747	int i = get_line(vc);
748	char *cp;
749	u_short saved_punc_mask = spk_punc_mask;
750	if (i == 0) {
751		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
752		return;
753	}
754	buf[i++] = '\n';
755	if (this_speakup_key == SAY_LINE_INDENT) {
756		cp = buf;
757		while (*cp == SPACE)
758			cp++;
759		synth_printf("%d, ", (cp - buf) + 1);
760	}
761	spk_punc_mask = spk_punc_masks[spk_reading_punc];
762	spkup_write(buf, i);
763	spk_punc_mask = saved_punc_mask;
764}
765
766static void say_prev_line(struct vc_data *vc)
767{
768	spk_parked |= 0x01;
769	if (spk_y == 0) {
770		announce_edge(vc, edge_top);
771		return;
772	}
773	spk_y--;
774	spk_pos -= vc->vc_size_row;
775	say_line(vc);
776}
777
778static void say_next_line(struct vc_data *vc)
779{
780	spk_parked |= 0x01;
781	if (spk_y == vc->vc_rows - 1) {
782		announce_edge(vc, edge_bottom);
783		return;
784	}
785	spk_y++;
786	spk_pos += vc->vc_size_row;
787	say_line(vc);
788}
789
790static int say_from_to(struct vc_data *vc, u_long from, u_long to,
791		       int read_punc)
792{
793	int i = 0;
794	u_char tmp;
795	u_short saved_punc_mask = spk_punc_mask;
796	spk_old_attr = spk_attr;
797	spk_attr = get_attributes((u_short *) from);
798	while (from < to) {
799		buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
800		from += 2;
801		if (i >= vc->vc_size_row)
802			break;
803	}
804	for (--i; i >= 0; i--)
805		if (buf[i] != SPACE)
806			break;
807	buf[++i] = SPACE;
808	buf[++i] = '\0';
809	if (i < 1)
810		return i;
811	if (read_punc)
812		spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
813	spkup_write(buf, i);
814	if (read_punc)
815		spk_punc_mask = saved_punc_mask;
816	return i - 1;
817}
818
819static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
820			     int read_punc)
821{
822	u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
823	u_long end = start + (to * 2);
824	start += from * 2;
825	if (say_from_to(vc, start, end, read_punc) <= 0)
826		if (cursor_track != read_all_mode)
827			synth_printf("%s\n", spk_msg_get(MSG_BLANK));
828}
829
830/* Sentence Reading Commands */
831
832static int currsentence;
833static int numsentences[2];
834static char *sentbufend[2];
835static char *sentmarks[2][10];
836static int currbuf;
837static int bn;
838static char sentbuf[2][256];
839
840static int say_sentence_num(int num, int prev)
841{
842	bn = currbuf;
843	currsentence = num + 1;
844	if (prev && --bn == -1)
845		bn = 1;
846
847	if (num > numsentences[bn])
848		return 0;
849
850	spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
851	return 1;
852}
853
854static int get_sentence_buf(struct vc_data *vc, int read_punc)
855{
856	u_long start, end;
857	int i, bn;
858	u_char tmp;
859
860	currbuf++;
861	if (currbuf == 2)
862		currbuf = 0;
863	bn = currbuf;
864	start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
865	end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
866
867	numsentences[bn] = 0;
868	sentmarks[bn][0] = &sentbuf[bn][0];
869	i = 0;
870	spk_old_attr = spk_attr;
871	spk_attr = get_attributes((u_short *) start);
872
873	while (start < end) {
874		sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
875		if (i > 0) {
876			if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
877			    && numsentences[bn] < 9) {
878				/* Sentence Marker */
879				numsentences[bn]++;
880				sentmarks[bn][numsentences[bn]] =
881				    &sentbuf[bn][i];
882			}
883		}
884		i++;
885		start += 2;
886		if (i >= vc->vc_size_row)
887			break;
888	}
889
890	for (--i; i >= 0; i--)
891		if (sentbuf[bn][i] != SPACE)
892			break;
893
894	if (i < 1)
895		return -1;
896
897	sentbuf[bn][++i] = SPACE;
898	sentbuf[bn][++i] = '\0';
899
900	sentbufend[bn] = &sentbuf[bn][i];
901	return numsentences[bn];
902}
903
904static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
905{
906	u_long start = vc->vc_origin, end;
907	if (from > 0)
908		start += from * vc->vc_size_row;
909	if (to > vc->vc_rows)
910		to = vc->vc_rows;
911	end = vc->vc_origin + (to * vc->vc_size_row);
912	for (from = start; from < end; from = to) {
913		to = from + vc->vc_size_row;
914		say_from_to(vc, from, to, 1);
915	}
916}
917
918static void say_screen(struct vc_data *vc)
919{
920	say_screen_from_to(vc, 0, vc->vc_rows);
921}
922
923static void speakup_win_say(struct vc_data *vc)
924{
925	u_long start, end, from, to;
926	if (win_start < 2) {
927		synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
928		return;
929	}
930	start = vc->vc_origin + (win_top * vc->vc_size_row);
931	end = vc->vc_origin + (win_bottom * vc->vc_size_row);
932	while (start <= end) {
933		from = start + (win_left * 2);
934		to = start + (win_right * 2);
935		say_from_to(vc, from, to, 1);
936		start += vc->vc_size_row;
937	}
938}
939
940static void top_edge(struct vc_data *vc)
941{
942	spk_parked |= 0x01;
943	spk_pos = vc->vc_origin + 2 * spk_x;
944	spk_y = 0;
945	say_line(vc);
946}
947
948static void bottom_edge(struct vc_data *vc)
949{
950	spk_parked |= 0x01;
951	spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
952	spk_y = vc->vc_rows - 1;
953	say_line(vc);
954}
955
956static void left_edge(struct vc_data *vc)
957{
958	spk_parked |= 0x01;
959	spk_pos -= spk_x * 2;
960	spk_x = 0;
961	say_char(vc);
962}
963
964static void right_edge(struct vc_data *vc)
965{
966	spk_parked |= 0x01;
967	spk_pos += (vc->vc_cols - spk_x - 1) * 2;
968	spk_x = vc->vc_cols - 1;
969	say_char(vc);
970}
971
972static void say_first_char(struct vc_data *vc)
973{
974	int i, len = get_line(vc);
975	u_char ch;
976	spk_parked |= 0x01;
977	if (len == 0) {
978		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
979		return;
980	}
981	for (i = 0; i < len; i++)
982		if (buf[i] != SPACE)
983			break;
984	ch = buf[i];
985	spk_pos -= (spk_x - i) * 2;
986	spk_x = i;
987	synth_printf("%d, ", ++i);
988	speak_char(ch);
989}
990
991static void say_last_char(struct vc_data *vc)
992{
993	int len = get_line(vc);
994	u_char ch;
995	spk_parked |= 0x01;
996	if (len == 0) {
997		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
998		return;
999	}
1000	ch = buf[--len];
1001	spk_pos -= (spk_x - len) * 2;
1002	spk_x = len;
1003	synth_printf("%d, ", ++len);
1004	speak_char(ch);
1005}
1006
1007static void say_position(struct vc_data *vc)
1008{
1009	synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1010		     vc->vc_num + 1);
1011	synth_printf("\n");
1012}
1013
1014/* Added by brianb */
1015static void say_char_num(struct vc_data *vc)
1016{
1017	u_char tmp;
1018	u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
1019	ch &= 0xff;
1020	synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1021}
1022
1023/* these are stub functions to keep keyboard.c happy. */
1024
1025static void say_from_top(struct vc_data *vc)
1026{
1027	say_screen_from_to(vc, 0, spk_y);
1028}
1029
1030static void say_to_bottom(struct vc_data *vc)
1031{
1032	say_screen_from_to(vc, spk_y, vc->vc_rows);
1033}
1034
1035static void say_from_left(struct vc_data *vc)
1036{
1037	say_line_from_to(vc, 0, spk_x, 1);
1038}
1039
1040static void say_to_right(struct vc_data *vc)
1041{
1042	say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1043}
1044
1045/* end of stub functions. */
1046
1047static void spkup_write(const char *in_buf, int count)
1048{
1049	static int rep_count;
1050	static u_char ch = '\0', old_ch = '\0';
1051	static u_short char_type, last_type;
1052	int in_count = count;
1053	spk_keydown = 0;
1054	while (count--) {
1055		if (cursor_track == read_all_mode) {
1056			/* Insert Sentence Index */
1057			if ((in_buf == sentmarks[bn][currsentence]) &&
1058			    (currsentence <= numsentences[bn]))
1059				synth_insert_next_index(currsentence++);
1060		}
1061		ch = (u_char) *in_buf++;
1062		char_type = spk_chartab[ch];
1063		if (ch == old_ch && !(char_type & B_NUM)) {
1064			if (++rep_count > 2)
1065				continue;
1066		} else {
1067			if ((last_type & CH_RPT) && rep_count > 2) {
1068				synth_printf(" ");
1069				synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1070					     ++rep_count);
1071				synth_printf(" ");
1072			}
1073			rep_count = 0;
1074		}
1075		if (ch == spk_lastkey) {
1076			rep_count = 0;
1077			if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1078				speak_char(ch);
1079		} else if (char_type & B_ALPHA) {
1080			if ((synth_flags & SF_DEC) && (last_type & PUNC))
1081				synth_buffer_add(SPACE);
1082			synth_printf("%c", ch);
1083		} else if (char_type & B_NUM) {
1084			rep_count = 0;
1085			synth_printf("%c", ch);
1086		} else if (char_type & spk_punc_mask) {
1087			speak_char(ch);
1088			char_type &= ~PUNC;	/* for dec nospell processing */
1089		} else if (char_type & SYNTH_OK) {
1090			/* these are usually puncts like . and , which synth
1091			 * needs for expression.
1092			 * suppress multiple to get rid of long pauses and
1093			 * clear repeat count
1094			 * so if someone has
1095			 * repeats on you don't get nothing repeated count */
1096			if (ch != old_ch)
1097				synth_printf("%c", ch);
1098			else
1099				rep_count = 0;
1100		} else {
1101/* send space and record position, if next is num overwrite space */
1102			if (old_ch != ch)
1103				synth_buffer_add(SPACE);
1104			else
1105				rep_count = 0;
1106		}
1107		old_ch = ch;
1108		last_type = char_type;
1109	}
1110	spk_lastkey = 0;
1111	if (in_count > 2 && rep_count > 2) {
1112		if (last_type & CH_RPT) {
1113			synth_printf(" ");
1114			synth_printf(spk_msg_get(MSG_REPEAT_DESC2), ++rep_count);
1115			synth_printf(" ");
1116		}
1117		rep_count = 0;
1118	}
1119}
1120
1121static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1122
1123static void read_all_doc(struct vc_data *vc);
1124static void cursor_done(u_long data);
1125static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1126
1127static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1128{
1129	unsigned long flags;
1130	if (synth == NULL || up_flag || spk_killed)
1131		return;
1132	spk_lock(flags);
1133	if (cursor_track == read_all_mode) {
1134		switch (value) {
1135		case KVAL(K_SHIFT):
1136			del_timer(&cursor_timer);
1137			spk_shut_up &= 0xfe;
1138			spk_do_flush();
1139			read_all_doc(vc);
1140			break;
1141		case KVAL(K_CTRL):
1142			del_timer(&cursor_timer);
1143			cursor_track = prev_cursor_track;
1144			spk_shut_up &= 0xfe;
1145			spk_do_flush();
1146			break;
1147		}
1148	} else {
1149		spk_shut_up &= 0xfe;
1150		spk_do_flush();
1151	}
1152	if (spk_say_ctrl && value < NUM_CTL_LABELS)
1153		synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1154	spk_unlock(flags);
1155}
1156
1157static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1158{
1159	unsigned long flags;
1160	spk_lock(flags);
1161	if (up_flag) {
1162		spk_lastkey = spk_keydown = 0;
1163		spk_unlock(flags);
1164		return;
1165	}
1166	if (synth == NULL || spk_killed) {
1167		spk_unlock(flags);
1168		return;
1169	}
1170	spk_shut_up &= 0xfe;
1171	spk_lastkey = value;
1172	spk_keydown++;
1173	spk_parked &= 0xfe;
1174	if (spk_key_echo == 2 && value >= MINECHOCHAR)
1175		speak_char(value);
1176	spk_unlock(flags);
1177}
1178
1179int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1180{
1181	int i = 0, states, key_data_len;
1182	const u_char *cp = key_info;
1183	u_char *cp1 = k_buffer;
1184	u_char ch, version, num_keys;
1185	version = *cp++;
1186	if (version != KEY_MAP_VER)
1187		return -1;
1188	num_keys = *cp;
1189	states = (int)cp[1];
1190	key_data_len = (states + 1) * (num_keys + 1);
1191	if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1192		return -2;
1193	memset(k_buffer, 0, SHIFT_TBL_SIZE);
1194	memset(spk_our_keys, 0, sizeof(spk_our_keys));
1195	spk_shift_table = k_buffer;
1196	spk_our_keys[0] = spk_shift_table;
1197	cp1 += SHIFT_TBL_SIZE;
1198	memcpy(cp1, cp, key_data_len + 3);
1199	/* get num_keys, states and data */
1200	cp1 += 2;		/* now pointing at shift states */
1201	for (i = 1; i <= states; i++) {
1202		ch = *cp1++;
1203		if (ch >= SHIFT_TBL_SIZE)
1204			return -3;
1205		spk_shift_table[ch] = i;
1206	}
1207	keymap_flags = *cp1++;
1208	while ((ch = *cp1)) {
1209		if (ch >= MAX_KEY)
1210			return -4;
1211		spk_our_keys[ch] = cp1;
1212		cp1 += states + 1;
1213	}
1214	return 0;
1215}
1216
1217static struct var_t spk_vars[] = {
1218	/* bell must be first to set high limit */
1219	{BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1220	{SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1221	{ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1222	{BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1223	{BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1224	{PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1225	{READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1226	{CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1227	{SAY_CONTROL, TOGGLE_0},
1228	{SAY_WORD_CTL, TOGGLE_0},
1229	{NO_INTERRUPT, TOGGLE_0},
1230	{KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1231	V_LAST_VAR
1232};
1233
1234static void toggle_cursoring(struct vc_data *vc)
1235{
1236	if (cursor_track == read_all_mode)
1237		cursor_track = prev_cursor_track;
1238	if (++cursor_track >= CT_Max)
1239		cursor_track = 0;
1240	synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1241}
1242
1243void spk_reset_default_chars(void)
1244{
1245	int i;
1246
1247	/* First, free any non-default */
1248	for (i = 0; i < 256; i++) {
1249		if ((spk_characters[i] != NULL)
1250		    && (spk_characters[i] != spk_default_chars[i]))
1251			kfree(spk_characters[i]);
1252	}
1253
1254	memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1255}
1256
1257void spk_reset_default_chartab(void)
1258{
1259	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1260}
1261
1262static const struct st_bits_data *pb_edit;
1263
1264static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1265{
1266	short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1267	if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1268		return -1;
1269	if (ch == SPACE) {
1270		synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1271		spk_special_handler = NULL;
1272		return 1;
1273	}
1274	if (mask < PUNC && !(ch_type & PUNC))
1275		return -1;
1276	spk_chartab[ch] ^= mask;
1277	speak_char(ch);
1278	synth_printf(" %s\n",
1279		     (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1280		     spk_msg_get(MSG_OFF));
1281	return 1;
1282}
1283
1284/* Allocation concurrency is protected by the console semaphore */
1285int speakup_allocate(struct vc_data *vc)
1286{
1287	int vc_num;
1288
1289	vc_num = vc->vc_num;
1290	if (speakup_console[vc_num] == NULL) {
1291		speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1292						  GFP_ATOMIC);
1293		if (speakup_console[vc_num] == NULL)
1294			return -ENOMEM;
1295		speakup_date(vc);
1296	} else if (!spk_parked)
1297		speakup_date(vc);
1298
1299	return 0;
1300}
1301
1302void speakup_deallocate(struct vc_data *vc)
1303{
1304	int vc_num;
1305
1306	vc_num = vc->vc_num;
1307	kfree(speakup_console[vc_num]);
1308	speakup_console[vc_num] = NULL;
1309}
1310
1311static u_char is_cursor;
1312static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1313static int cursor_con;
1314
1315static void reset_highlight_buffers(struct vc_data *);
1316
1317static int read_all_key;
1318
1319static void start_read_all_timer(struct vc_data *vc, int command);
1320
1321enum {
1322	RA_NOTHING,
1323	RA_NEXT_SENT,
1324	RA_PREV_LINE,
1325	RA_NEXT_LINE,
1326	RA_PREV_SENT,
1327	RA_DOWN_ARROW,
1328	RA_TIMER,
1329	RA_FIND_NEXT_SENT,
1330	RA_FIND_PREV_SENT,
1331};
1332
1333static void kbd_fakekey2(struct vc_data *vc, int command)
1334{
1335	del_timer(&cursor_timer);
1336	speakup_fake_down_arrow();
1337	start_read_all_timer(vc, command);
1338}
1339
1340static void read_all_doc(struct vc_data *vc)
1341{
1342	if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1343		return;
1344	if (!synth_supports_indexing())
1345		return;
1346	if (cursor_track != read_all_mode)
1347		prev_cursor_track = cursor_track;
1348	cursor_track = read_all_mode;
1349	spk_reset_index_count(0);
1350	if (get_sentence_buf(vc, 0) == -1)
1351		kbd_fakekey2(vc, RA_DOWN_ARROW);
1352	else {
1353		say_sentence_num(0, 0);
1354		synth_insert_next_index(0);
1355		start_read_all_timer(vc, RA_TIMER);
1356	}
1357}
1358
1359static void stop_read_all(struct vc_data *vc)
1360{
1361	del_timer(&cursor_timer);
1362	cursor_track = prev_cursor_track;
1363	spk_shut_up &= 0xfe;
1364	spk_do_flush();
1365}
1366
1367static void start_read_all_timer(struct vc_data *vc, int command)
1368{
1369	struct var_t *cursor_timeout;
1370
1371	cursor_con = vc->vc_num;
1372	read_all_key = command;
1373	cursor_timeout = spk_get_var(CURSOR_TIME);
1374	mod_timer(&cursor_timer,
1375		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1376}
1377
1378static void handle_cursor_read_all(struct vc_data *vc, int command)
1379{
1380	int indcount, sentcount, rv, sn;
1381
1382	switch (command) {
1383	case RA_NEXT_SENT:
1384		/* Get Current Sentence */
1385		spk_get_index_count(&indcount, &sentcount);
1386		/*printk("%d %d  ", indcount, sentcount); */
1387		spk_reset_index_count(sentcount + 1);
1388		if (indcount == 1) {
1389			if (!say_sentence_num(sentcount + 1, 0)) {
1390				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1391				return;
1392			}
1393			synth_insert_next_index(0);
1394		} else {
1395			sn = 0;
1396			if (!say_sentence_num(sentcount + 1, 1)) {
1397				sn = 1;
1398				spk_reset_index_count(sn);
1399			} else
1400				synth_insert_next_index(0);
1401			if (!say_sentence_num(sn, 0)) {
1402				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1403				return;
1404			}
1405			synth_insert_next_index(0);
1406		}
1407		start_read_all_timer(vc, RA_TIMER);
1408		break;
1409	case RA_PREV_SENT:
1410		break;
1411	case RA_NEXT_LINE:
1412		read_all_doc(vc);
1413		break;
1414	case RA_PREV_LINE:
1415		break;
1416	case RA_DOWN_ARROW:
1417		if (get_sentence_buf(vc, 0) == -1) {
1418			kbd_fakekey2(vc, RA_DOWN_ARROW);
1419		} else {
1420			say_sentence_num(0, 0);
1421			synth_insert_next_index(0);
1422			start_read_all_timer(vc, RA_TIMER);
1423		}
1424		break;
1425	case RA_FIND_NEXT_SENT:
1426		rv = get_sentence_buf(vc, 0);
1427		if (rv == -1)
1428			read_all_doc(vc);
1429		if (rv == 0)
1430			kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1431		else {
1432			say_sentence_num(1, 0);
1433			synth_insert_next_index(0);
1434			start_read_all_timer(vc, RA_TIMER);
1435		}
1436		break;
1437	case RA_FIND_PREV_SENT:
1438		break;
1439	case RA_TIMER:
1440		spk_get_index_count(&indcount, &sentcount);
1441		if (indcount < 2)
1442			kbd_fakekey2(vc, RA_DOWN_ARROW);
1443		else
1444			start_read_all_timer(vc, RA_TIMER);
1445		break;
1446	}
1447}
1448
1449static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1450{
1451	unsigned long flags;
1452	spk_lock(flags);
1453	if (cursor_track == read_all_mode) {
1454		spk_parked &= 0xfe;
1455		if (synth == NULL || up_flag || spk_shut_up) {
1456			spk_unlock(flags);
1457			return NOTIFY_STOP;
1458		}
1459		del_timer(&cursor_timer);
1460		spk_shut_up &= 0xfe;
1461		spk_do_flush();
1462		start_read_all_timer(vc, value + 1);
1463		spk_unlock(flags);
1464		return NOTIFY_STOP;
1465	}
1466	spk_unlock(flags);
1467	return NOTIFY_OK;
1468}
1469
1470static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1471{
1472	unsigned long flags;
1473	struct var_t *cursor_timeout;
1474
1475	spk_lock(flags);
1476	spk_parked &= 0xfe;
1477	if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
1478		spk_unlock(flags);
1479		return;
1480	}
1481	spk_shut_up &= 0xfe;
1482	if (spk_no_intr)
1483		spk_do_flush();
1484/* the key press flushes if !no_inter but we want to flush on cursor
1485 * moves regardless of no_inter state */
1486	is_cursor = value + 1;
1487	old_cursor_pos = vc->vc_pos;
1488	old_cursor_x = vc->vc_x;
1489	old_cursor_y = vc->vc_y;
1490	speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1491	cursor_con = vc->vc_num;
1492	if (cursor_track == CT_Highlight)
1493		reset_highlight_buffers(vc);
1494	cursor_timeout = spk_get_var(CURSOR_TIME);
1495	mod_timer(&cursor_timer,
1496		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1497	spk_unlock(flags);
1498}
1499
1500static void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1501{
1502	int i, bi, hi;
1503	int vc_num = vc->vc_num;
1504
1505	bi = ((vc->vc_attr & 0x70) >> 4);
1506	hi = speakup_console[vc_num]->ht.highsize[bi];
1507
1508	i = 0;
1509	if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1510		speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1511		speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1512		speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1513	}
1514	while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1515		if ((ic[i] > 32) && (ic[i] < 127)) {
1516			speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1517			hi++;
1518		} else if ((ic[i] == 32) && (hi != 0)) {
1519			if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1520			    32) {
1521				speakup_console[vc_num]->ht.highbuf[bi][hi] =
1522				    ic[i];
1523				hi++;
1524			}
1525		}
1526		i++;
1527	}
1528	speakup_console[vc_num]->ht.highsize[bi] = hi;
1529}
1530
1531static void reset_highlight_buffers(struct vc_data *vc)
1532{
1533	int i;
1534	int vc_num = vc->vc_num;
1535	for (i = 0; i < 8; i++)
1536		speakup_console[vc_num]->ht.highsize[i] = 0;
1537}
1538
1539static int count_highlight_color(struct vc_data *vc)
1540{
1541	int i, bg;
1542	int cc;
1543	int vc_num = vc->vc_num;
1544	u16 ch;
1545	u16 *start = (u16 *) vc->vc_origin;
1546
1547	for (i = 0; i < 8; i++)
1548		speakup_console[vc_num]->ht.bgcount[i] = 0;
1549
1550	for (i = 0; i < vc->vc_rows; i++) {
1551		u16 *end = start + vc->vc_cols * 2;
1552		u16 *ptr;
1553		for (ptr = start; ptr < end; ptr++) {
1554			ch = get_attributes(ptr);
1555			bg = (ch & 0x70) >> 4;
1556			speakup_console[vc_num]->ht.bgcount[bg]++;
1557		}
1558		start += vc->vc_size_row;
1559	}
1560
1561	cc = 0;
1562	for (i = 0; i < 8; i++)
1563		if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1564			cc++;
1565	return cc;
1566}
1567
1568static int get_highlight_color(struct vc_data *vc)
1569{
1570	int i, j;
1571	unsigned int cptr[8], tmp;
1572	int vc_num = vc->vc_num;
1573
1574	for (i = 0; i < 8; i++)
1575		cptr[i] = i;
1576
1577	for (i = 0; i < 7; i++)
1578		for (j = i + 1; j < 8; j++)
1579			if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1580			    speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1581				tmp = cptr[i];
1582				cptr[i] = cptr[j];
1583				cptr[j] = tmp;
1584			}
1585
1586	for (i = 0; i < 8; i++)
1587		if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1588			if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1589				return cptr[i];
1590	return -1;
1591}
1592
1593static int speak_highlight(struct vc_data *vc)
1594{
1595	int hc, d;
1596	int vc_num = vc->vc_num;
1597	if (count_highlight_color(vc) == 1)
1598		return 0;
1599	hc = get_highlight_color(vc);
1600	if (hc != -1) {
1601		d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1602		if ((d == 1) || (d == -1))
1603			if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1604				return 0;
1605		spk_parked |= 0x01;
1606		spk_do_flush();
1607		spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1608			    speakup_console[vc_num]->ht.highsize[hc]);
1609		spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1610		spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1611		spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1612		return 1;
1613	}
1614	return 0;
1615}
1616
1617static void cursor_done(u_long data)
1618{
1619	struct vc_data *vc = vc_cons[cursor_con].d;
1620	unsigned long flags;
1621	del_timer(&cursor_timer);
1622	spk_lock(flags);
1623	if (cursor_con != fg_console) {
1624		is_cursor = 0;
1625		goto out;
1626	}
1627	speakup_date(vc);
1628	if (win_enabled) {
1629		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1630		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1631			spk_keydown = is_cursor = 0;
1632			goto out;
1633		}
1634	}
1635	if (cursor_track == read_all_mode) {
1636		handle_cursor_read_all(vc, read_all_key);
1637		goto out;
1638	}
1639	if (cursor_track == CT_Highlight) {
1640		if (speak_highlight(vc)) {
1641			spk_keydown = is_cursor = 0;
1642			goto out;
1643		}
1644	}
1645	if (cursor_track == CT_Window)
1646		speakup_win_say(vc);
1647	else if (is_cursor == 1 || is_cursor == 4)
1648		say_line_from_to(vc, 0, vc->vc_cols, 0);
1649	else
1650		say_char(vc);
1651	spk_keydown = is_cursor = 0;
1652out:
1653	spk_unlock(flags);
1654}
1655
1656/* called by: vt_notifier_call() */
1657static void speakup_bs(struct vc_data *vc)
1658{
1659	unsigned long flags;
1660	if (!speakup_console[vc->vc_num])
1661		return;
1662	if (!spk_trylock(flags))
1663		/* Speakup output, discard */
1664		return;
1665	if (!spk_parked)
1666		speakup_date(vc);
1667	if (spk_shut_up || synth == NULL) {
1668		spk_unlock(flags);
1669		return;
1670	}
1671	if (vc->vc_num == fg_console && spk_keydown) {
1672		spk_keydown = 0;
1673		if (!is_cursor)
1674			say_char(vc);
1675	}
1676	spk_unlock(flags);
1677}
1678
1679/* called by: vt_notifier_call() */
1680static void speakup_con_write(struct vc_data *vc, const char *str, int len)
1681{
1682	unsigned long flags;
1683	if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1684		return;
1685	if (!spk_trylock(flags))
1686		/* Speakup output, discard */
1687		return;
1688	if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1689		bleep(3);
1690	if ((is_cursor) || (cursor_track == read_all_mode)) {
1691		if (cursor_track == CT_Highlight)
1692			update_color_buffer(vc, str, len);
1693		spk_unlock(flags);
1694		return;
1695	}
1696	if (win_enabled) {
1697		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
1698		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1699			spk_unlock(flags);
1700			return;
1701		}
1702	}
1703
1704	spkup_write(str, len);
1705	spk_unlock(flags);
1706}
1707
1708void speakup_con_update(struct vc_data *vc)
1709{
1710	unsigned long flags;
1711	if (speakup_console[vc->vc_num] == NULL || spk_parked)
1712		return;
1713	if (!spk_trylock(flags))
1714		/* Speakup output, discard */
1715		return;
1716	speakup_date(vc);
1717	spk_unlock(flags);
1718}
1719
1720static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1721{
1722	unsigned long flags;
1723	int on_off = 2;
1724	char *label;
1725	if (synth == NULL || up_flag || spk_killed)
1726		return;
1727	spk_lock(flags);
1728	spk_shut_up &= 0xfe;
1729	if (spk_no_intr)
1730		spk_do_flush();
1731	switch (value) {
1732	case KVAL(K_CAPS):
1733		label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1734		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1735		break;
1736	case KVAL(K_NUM):
1737		label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1738		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1739		break;
1740	case KVAL(K_HOLD):
1741		label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1742		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1743		if (speakup_console[vc->vc_num])
1744			speakup_console[vc->vc_num]->tty_stopped = on_off;
1745		break;
1746	default:
1747		spk_parked &= 0xfe;
1748		spk_unlock(flags);
1749		return;
1750	}
1751	if (on_off < 2)
1752		synth_printf("%s %s\n",
1753			     label, spk_msg_get(MSG_STATUS_START + on_off));
1754	spk_unlock(flags);
1755}
1756
1757static int inc_dec_var(u_char value)
1758{
1759	struct st_var_header *p_header;
1760	struct var_t *var_data;
1761	char num_buf[32];
1762	char *cp = num_buf;
1763	char *pn;
1764	int var_id = (int)value - VAR_START;
1765	int how = (var_id & 1) ? E_INC : E_DEC;
1766	var_id = var_id / 2 + FIRST_SET_VAR;
1767	p_header = spk_get_var_header(var_id);
1768	if (p_header == NULL)
1769		return -1;
1770	if (p_header->var_type != VAR_NUM)
1771		return -1;
1772	var_data = p_header->data;
1773	if (spk_set_num_var(1, p_header, how) != 0)
1774		return -1;
1775	if (!spk_close_press) {
1776		for (pn = p_header->name; *pn; pn++) {
1777			if (*pn == '_')
1778				*cp = SPACE;
1779			else
1780				*cp++ = *pn;
1781		}
1782	}
1783	snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1784		 var_data->u.n.value);
1785	synth_printf("%s", num_buf);
1786	return 0;
1787}
1788
1789static void speakup_win_set(struct vc_data *vc)
1790{
1791	char info[40];
1792	if (win_start > 1) {
1793		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1794		return;
1795	}
1796	if (spk_x < win_left || spk_y < win_top) {
1797		synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1798		return;
1799	}
1800	if (win_start && spk_x == win_left && spk_y == win_top) {
1801		win_left = 0;
1802		win_right = vc->vc_cols - 1;
1803		win_bottom = spk_y;
1804		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1805			 (int)win_top + 1);
1806	} else {
1807		if (!win_start) {
1808			win_top = spk_y;
1809			win_left = spk_x;
1810		} else {
1811			win_bottom = spk_y;
1812			win_right = spk_x;
1813		}
1814		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1815			 (win_start) ? spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1816			 (int)spk_y + 1, (int)spk_x + 1);
1817	}
1818	synth_printf("%s\n", info);
1819	win_start++;
1820}
1821
1822static void speakup_win_clear(struct vc_data *vc)
1823{
1824	win_top = win_bottom = 0;
1825	win_left = win_right = 0;
1826	win_start = 0;
1827	synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1828}
1829
1830static void speakup_win_enable(struct vc_data *vc)
1831{
1832	if (win_start < 2) {
1833		synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1834		return;
1835	}
1836	win_enabled ^= 1;
1837	if (win_enabled)
1838		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1839	else
1840		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1841}
1842
1843static void speakup_bits(struct vc_data *vc)
1844{
1845	int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1846	if (spk_special_handler != NULL || val < 1 || val > 6) {
1847		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1848		return;
1849	}
1850	pb_edit = &spk_punc_info[val];
1851	synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1852	spk_special_handler = edit_bits;
1853}
1854
1855static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1856{
1857	static u_char goto_buf[8];
1858	static int num;
1859	int maxlen, go_pos;
1860	char *cp;
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	cp = speakup_s2i(goto_buf, &go_pos);
1896	goto_pos = (u_long) go_pos;
1897	if (*cp == 'x') {
1898		if (*goto_buf < '0')
1899			goto_pos += spk_x;
1900		else
1901			goto_pos--;
1902		if (goto_pos < 0)
1903			goto_pos = 0;
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
1911			goto_pos--;
1912		if (goto_pos < 0)
1913			goto_pos = 0;
1914		if (goto_pos >= vc->vc_rows)
1915			goto_pos = vc->vc_rows - 1;
1916		goto_x = 0;
1917	}
1918	goto_buf[num = 0] = '\0';
1919do_goto:
1920	spk_special_handler = NULL;
1921	spk_parked |= 0x01;
1922	if (goto_x) {
1923		spk_pos -= spk_x * 2;
1924		spk_x = goto_pos;
1925		spk_pos += goto_pos * 2;
1926		say_word(vc);
1927	} else {
1928		spk_y = goto_pos;
1929		spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1930		say_line(vc);
1931	}
1932	return 1;
1933}
1934
1935static void speakup_goto(struct vc_data *vc)
1936{
1937	if (spk_special_handler != NULL) {
1938		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1939		return;
1940	}
1941	synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1942	spk_special_handler = handle_goto;
1943	return;
1944}
1945
1946static void speakup_help(struct vc_data *vc)
1947{
1948	spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1949}
1950
1951static void do_nothing(struct vc_data *vc)
1952{
1953	return;			/* flush done in do_spkup */
1954}
1955
1956static u_char key_speakup, spk_key_locked;
1957
1958static void speakup_lock(struct vc_data *vc)
1959{
1960	if (!spk_key_locked)
1961		spk_key_locked = key_speakup = 16;
1962	else
1963		spk_key_locked = key_speakup = 0;
1964}
1965
1966typedef void (*spkup_hand) (struct vc_data *);
1967spkup_hand spkup_handler[] = {
1968	/* must be ordered same as defines in speakup.h */
1969	do_nothing, speakup_goto, speech_kill, speakup_shut_up,
1970	speakup_cut, speakup_paste, say_first_char, say_last_char,
1971	say_char, say_prev_char, say_next_char,
1972	say_word, say_prev_word, say_next_word,
1973	say_line, say_prev_line, say_next_line,
1974	top_edge, bottom_edge, left_edge, right_edge,
1975	spell_word, spell_word, say_screen,
1976	say_position, say_attributes,
1977	speakup_off, speakup_parked, say_line,	/* this is for indent */
1978	say_from_top, say_to_bottom,
1979	say_from_left, say_to_right,
1980	say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
1981	speakup_bits, speakup_bits, speakup_bits,
1982	speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
1983	speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
1984};
1985
1986static void do_spkup(struct vc_data *vc, u_char value)
1987{
1988	if (spk_killed && value != SPEECH_KILL)
1989		return;
1990	spk_keydown = 0;
1991	spk_lastkey = 0;
1992	spk_shut_up &= 0xfe;
1993	this_speakup_key = value;
1994	if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
1995		spk_do_flush();
1996		(*spkup_handler[value]) (vc);
1997	} else {
1998		if (inc_dec_var(value) < 0)
1999			bleep(9);
2000	}
2001}
2002
2003static const char *pad_chars = "0123456789+-*/\015,.?()";
2004
2005int
2006speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2007	    int up_flag)
2008{
2009	unsigned long flags;
2010	int kh;
2011	u_char *key_info;
2012	u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2013	u_char shift_info, offset;
2014	int ret = 0;
2015	if (synth == NULL)
2016		return 0;
2017
2018	spk_lock(flags);
2019	tty = vc->port.tty;
2020	if (type >= 0xf0)
2021		type -= 0xf0;
2022	if (type == KT_PAD
2023		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
2024		if (up_flag) {
2025			spk_keydown = 0;
2026			goto out;
2027		}
2028		value = spk_lastkey = pad_chars[value];
2029		spk_keydown++;
2030		spk_parked &= 0xfe;
2031		goto no_map;
2032	}
2033	if (keycode >= MAX_KEY)
2034		goto no_map;
2035	key_info = spk_our_keys[keycode];
2036	if (key_info == 0)
2037		goto no_map;
2038	/* Check valid read all mode keys */
2039	if ((cursor_track == read_all_mode) && (!up_flag)) {
2040		switch (value) {
2041		case KVAL(K_DOWN):
2042		case KVAL(K_UP):
2043		case KVAL(K_LEFT):
2044		case KVAL(K_RIGHT):
2045		case KVAL(K_PGUP):
2046		case KVAL(K_PGDN):
2047			break;
2048		default:
2049			stop_read_all(vc);
2050			break;
2051		}
2052	}
2053	shift_info = (shift_state & 0x0f) + key_speakup;
2054	offset = spk_shift_table[shift_info];
2055	if (offset) {
2056		new_key = key_info[offset];
2057		if (new_key) {
2058			ret = 1;
2059			if (new_key == SPK_KEY) {
2060				if (!spk_key_locked)
2061					key_speakup = (up_flag) ? 0 : 16;
2062				if (up_flag || spk_killed)
2063					goto out;
2064				spk_shut_up &= 0xfe;
2065				spk_do_flush();
2066				goto out;
2067			}
2068			if (up_flag)
2069				goto out;
2070			if (last_keycode == keycode &&
2071			    last_spk_jiffy + MAX_DELAY > jiffies) {
2072				spk_close_press = 1;
2073				offset = spk_shift_table[shift_info + 32];
2074				/* double press? */
2075				if (offset && key_info[offset])
2076					new_key = key_info[offset];
2077			}
2078			last_keycode = keycode;
2079			last_spk_jiffy = jiffies;
2080			type = KT_SPKUP;
2081			value = new_key;
2082		}
2083	}
2084no_map:
2085	if (type == KT_SPKUP && spk_special_handler == NULL) {
2086		do_spkup(vc, new_key);
2087		spk_close_press = 0;
2088		ret = 1;
2089		goto out;
2090	}
2091	if (up_flag || spk_killed || type == KT_SHIFT)
2092		goto out;
2093	spk_shut_up &= 0xfe;
2094	kh = (value == KVAL(K_DOWN))
2095	    || (value == KVAL(K_UP))
2096	    || (value == KVAL(K_LEFT))
2097	    || (value == KVAL(K_RIGHT));
2098	if ((cursor_track != read_all_mode) || !kh)
2099		if (!spk_no_intr)
2100			spk_do_flush();
2101	if (spk_special_handler) {
2102		if (type == KT_SPEC && value == 1) {
2103			value = '\n';
2104			type = KT_LATIN;
2105		} else if (type == KT_LETTER)
2106			type = KT_LATIN;
2107		else if (value == 0x7f)
2108			value = 8;	/* make del = backspace */
2109		ret = (*spk_special_handler) (vc, type, value, keycode);
2110		spk_close_press = 0;
2111		if (ret < 0)
2112			bleep(9);
2113		goto out;
2114	}
2115	last_keycode = 0;
2116out:
2117	spk_unlock(flags);
2118	return ret;
2119}
2120
2121static int keyboard_notifier_call(struct notifier_block *nb,
2122				  unsigned long code, void *_param)
2123{
2124	struct keyboard_notifier_param *param = _param;
2125	struct vc_data *vc = param->vc;
2126	int up = !param->down;
2127	int ret = NOTIFY_OK;
2128	static int keycode;	/* to hold the current keycode */
2129
2130	if (vc->vc_mode == KD_GRAPHICS)
2131		return ret;
2132
2133	/*
2134	 * First, determine whether we are handling a fake keypress on
2135	 * the current processor.  If we are, then return NOTIFY_OK,
2136	 * to pass the keystroke up the chain.  This prevents us from
2137	 * trying to take the Speakup lock while it is held by the
2138	 * processor on which the simulated keystroke was generated.
2139	 * Also, the simulated keystrokes should be ignored by Speakup.
2140	 */
2141
2142	if (speakup_fake_key_pressed())
2143		return ret;
2144
2145	switch (code) {
2146	case KBD_KEYCODE:
2147		/* speakup requires keycode and keysym currently */
2148		keycode = param->value;
2149		break;
2150	case KBD_UNBOUND_KEYCODE:
2151		/* not used yet */
2152		break;
2153	case KBD_UNICODE:
2154		/* not used yet */
2155		break;
2156	case KBD_KEYSYM:
2157		if (speakup_key(vc, param->shift, keycode, param->value, up))
2158			ret = NOTIFY_STOP;
2159		else if (KTYP(param->value) == KT_CUR)
2160			ret = pre_handle_cursor(vc, KVAL(param->value), up);
2161		break;
2162	case KBD_POST_KEYSYM:{
2163			unsigned char type = KTYP(param->value) - 0xf0;
2164			unsigned char val = KVAL(param->value);
2165			switch (type) {
2166			case KT_SHIFT:
2167				do_handle_shift(vc, val, up);
2168				break;
2169			case KT_LATIN:
2170			case KT_LETTER:
2171				do_handle_latin(vc, val, up);
2172				break;
2173			case KT_CUR:
2174				do_handle_cursor(vc, val, up);
2175				break;
2176			case KT_SPEC:
2177				do_handle_spec(vc, val, up);
2178				break;
2179			}
2180			break;
2181		}
2182	}
2183	return ret;
2184}
2185
2186static int vt_notifier_call(struct notifier_block *nb,
2187			    unsigned long code, void *_param)
2188{
2189	struct vt_notifier_param *param = _param;
2190	struct vc_data *vc = param->vc;
2191	switch (code) {
2192	case VT_ALLOCATE:
2193		if (vc->vc_mode == KD_TEXT)
2194			speakup_allocate(vc);
2195		break;
2196	case VT_DEALLOCATE:
2197		speakup_deallocate(vc);
2198		break;
2199	case VT_WRITE:
2200		if (param->c == '\b')
2201			speakup_bs(vc);
2202		else if (param->c < 0x100) {
2203			char d = param->c;
2204			speakup_con_write(vc, &d, 1);
2205		}
2206		break;
2207	case VT_UPDATE:
2208		speakup_con_update(vc);
2209		break;
2210	}
2211	return NOTIFY_OK;
2212}
2213
2214/* called by: module_exit() */
2215static void __exit speakup_exit(void)
2216{
2217	int i;
2218
2219	unregister_keyboard_notifier(&keyboard_notifier_block);
2220	unregister_vt_notifier(&vt_notifier_block);
2221	speakup_unregister_devsynth();
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(0, 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