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