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