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