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