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