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