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