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