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