18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* speakup.c 38c2ecf20Sopenharmony_ci * review functions for the speakup screen review package. 48c2ecf20Sopenharmony_ci * originally written by: Kirk Reiser and Andy Berdan. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * extensively modified by David Borowski. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci ** Copyright (C) 1998 Kirk Reiser. 98c2ecf20Sopenharmony_ci * Copyright (C) 2003 David Borowski. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/vt.h> 148c2ecf20Sopenharmony_ci#include <linux/tty.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> /* __get_free_page() and friends */ 168c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 178c2ecf20Sopenharmony_ci#include <linux/ctype.h> 188c2ecf20Sopenharmony_ci#include <linux/selection.h> 198c2ecf20Sopenharmony_ci#include <linux/unistd.h> 208c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 218c2ecf20Sopenharmony_ci#include <linux/kthread.h> 228c2ecf20Sopenharmony_ci#include <linux/keyboard.h> /* for KT_SHIFT */ 238c2ecf20Sopenharmony_ci#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */ 248c2ecf20Sopenharmony_ci#include <linux/input.h> 258c2ecf20Sopenharmony_ci#include <linux/kmod.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* speakup_*_selection */ 288c2ecf20Sopenharmony_ci#include <linux/module.h> 298c2ecf20Sopenharmony_ci#include <linux/sched.h> 308c2ecf20Sopenharmony_ci#include <linux/slab.h> 318c2ecf20Sopenharmony_ci#include <linux/types.h> 328c2ecf20Sopenharmony_ci#include <linux/consolemap.h> 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 358c2ecf20Sopenharmony_ci#include <linux/notifier.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <linux/uaccess.h> /* copy_from|to|user() and others */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#include "spk_priv.h" 408c2ecf20Sopenharmony_ci#include "speakup.h" 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define MAX_DELAY msecs_to_jiffies(500) 438c2ecf20Sopenharmony_ci#define MINECHOCHAR SPACE 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>"); 468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>"); 478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Speakup console speech"); 488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 498c2ecf20Sopenharmony_ciMODULE_VERSION(SPEAKUP_VERSION); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cichar *synth_name; 528c2ecf20Sopenharmony_cimodule_param_named(synth, synth_name, charp, 0444); 538c2ecf20Sopenharmony_cimodule_param_named(quiet, spk_quiet_boot, bool, 0444); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(synth, "Synth to start if speakup is built in."); 568c2ecf20Sopenharmony_ciMODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found."); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cispecial_func spk_special_handler; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cishort spk_pitch_shift, synth_flags; 618c2ecf20Sopenharmony_cistatic u16 buf[256]; 628c2ecf20Sopenharmony_ciint spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10; 638c2ecf20Sopenharmony_ciint spk_no_intr, spk_spell_delay; 648c2ecf20Sopenharmony_ciint spk_key_echo, spk_say_word_ctl; 658c2ecf20Sopenharmony_ciint spk_say_ctrl, spk_bell_pos; 668c2ecf20Sopenharmony_cishort spk_punc_mask; 678c2ecf20Sopenharmony_ciint spk_punc_level, spk_reading_punc; 688c2ecf20Sopenharmony_cichar spk_str_caps_start[MAXVARLEN + 1] = "\0"; 698c2ecf20Sopenharmony_cichar spk_str_caps_stop[MAXVARLEN + 1] = "\0"; 708c2ecf20Sopenharmony_cichar spk_str_pause[MAXVARLEN + 1] = "\0"; 718c2ecf20Sopenharmony_cibool spk_paused; 728c2ecf20Sopenharmony_ciconst struct st_bits_data spk_punc_info[] = { 738c2ecf20Sopenharmony_ci {"none", "", 0}, 748c2ecf20Sopenharmony_ci {"some", "/$%&@", SOME}, 758c2ecf20Sopenharmony_ci {"most", "$%&#()=+*/@^<>|\\", MOST}, 768c2ecf20Sopenharmony_ci {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC}, 778c2ecf20Sopenharmony_ci {"delimiters", "", B_WDLM}, 788c2ecf20Sopenharmony_ci {"repeats", "()", CH_RPT}, 798c2ecf20Sopenharmony_ci {"extended numeric", "", B_EXNUM}, 808c2ecf20Sopenharmony_ci {"symbols", "", B_SYM}, 818c2ecf20Sopenharmony_ci {NULL, NULL} 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic char mark_cut_flag; 858c2ecf20Sopenharmony_ci#define MAX_KEY 160 868c2ecf20Sopenharmony_cistatic u_char *spk_shift_table; 878c2ecf20Sopenharmony_ciu_char *spk_our_keys[MAX_KEY]; 888c2ecf20Sopenharmony_ciu_char spk_key_buf[600]; 898c2ecf20Sopenharmony_ciconst u_char spk_key_defaults[] = { 908c2ecf20Sopenharmony_ci#include "speakupmap.h" 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Speakup Cursor Track Variables */ 948c2ecf20Sopenharmony_cistatic int cursor_track = 1, prev_cursor_track = 1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* cursor track modes, must be ordered same as cursor_msgs */ 978c2ecf20Sopenharmony_cienum { 988c2ecf20Sopenharmony_ci CT_Off = 0, 998c2ecf20Sopenharmony_ci CT_On, 1008c2ecf20Sopenharmony_ci CT_Highlight, 1018c2ecf20Sopenharmony_ci CT_Window, 1028c2ecf20Sopenharmony_ci CT_Max 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define read_all_mode CT_Max 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic struct tty_struct *tty; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void spkup_write(const u16 *in_buf, int count); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic char *phonetic[] = { 1128c2ecf20Sopenharmony_ci "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel", 1138c2ecf20Sopenharmony_ci "india", "juliett", "keelo", "leema", "mike", "november", "oscar", 1148c2ecf20Sopenharmony_ci "papa", 1158c2ecf20Sopenharmony_ci "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey", 1168c2ecf20Sopenharmony_ci "x ray", "yankee", "zulu" 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* array of 256 char pointers (one for each character description) 1208c2ecf20Sopenharmony_ci * initialized to default_chars and user selectable via 1218c2ecf20Sopenharmony_ci * /proc/speakup/characters 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cichar *spk_characters[256]; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cichar *spk_default_chars[256] = { 1268c2ecf20Sopenharmony_ci/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g", 1278c2ecf20Sopenharmony_ci/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o", 1288c2ecf20Sopenharmony_ci/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w", 1298c2ecf20Sopenharmony_ci/*024*/ "^x", "^y", "^z", "control", "control", "control", "control", 1308c2ecf20Sopenharmony_ci "control", 1318c2ecf20Sopenharmony_ci/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and", 1328c2ecf20Sopenharmony_ci "tick", 1338c2ecf20Sopenharmony_ci/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash", 1348c2ecf20Sopenharmony_ci "dot", 1358c2ecf20Sopenharmony_ci "slash", 1368c2ecf20Sopenharmony_ci/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven", 1378c2ecf20Sopenharmony_ci "eight", "nine", 1388c2ecf20Sopenharmony_ci/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at", 1398c2ecf20Sopenharmony_ci/*065*/ "EIGH", "B", "C", "D", "E", "F", "G", 1408c2ecf20Sopenharmony_ci/*072*/ "H", "I", "J", "K", "L", "M", "N", "O", 1418c2ecf20Sopenharmony_ci/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X", 1428c2ecf20Sopenharmony_ci/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket", 1438c2ecf20Sopenharmony_ci "caret", 1448c2ecf20Sopenharmony_ci "line", 1458c2ecf20Sopenharmony_ci/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g", 1468c2ecf20Sopenharmony_ci/*104*/ "h", "i", "j", "k", "l", "m", "n", "o", 1478c2ecf20Sopenharmony_ci/*112*/ "p", "q", "r", "s", "t", "u", "v", "w", 1488c2ecf20Sopenharmony_ci/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh", 1498c2ecf20Sopenharmony_ci/*127*/ "del", "control", "control", "control", "control", "control", 1508c2ecf20Sopenharmony_ci "control", "control", "control", "control", "control", 1518c2ecf20Sopenharmony_ci/*138*/ "control", "control", "control", "control", "control", 1528c2ecf20Sopenharmony_ci "control", "control", "control", "control", "control", 1538c2ecf20Sopenharmony_ci "control", "control", 1548c2ecf20Sopenharmony_ci/*150*/ "control", "control", "control", "control", "control", 1558c2ecf20Sopenharmony_ci "control", "control", "control", "control", "control", 1568c2ecf20Sopenharmony_ci/*160*/ "nbsp", "inverted bang", 1578c2ecf20Sopenharmony_ci/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section", 1588c2ecf20Sopenharmony_ci/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle", 1598c2ecf20Sopenharmony_ci/*172*/ "not", "soft hyphen", "registered", "macron", 1608c2ecf20Sopenharmony_ci/*176*/ "degrees", "plus or minus", "super two", "super three", 1618c2ecf20Sopenharmony_ci/*180*/ "acute accent", "micro", "pilcrow", "middle dot", 1628c2ecf20Sopenharmony_ci/*184*/ "cedilla", "super one", "male ordinal", "double right angle", 1638c2ecf20Sopenharmony_ci/*188*/ "one quarter", "one half", "three quarters", 1648c2ecf20Sopenharmony_ci "inverted question", 1658c2ecf20Sopenharmony_ci/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT", 1668c2ecf20Sopenharmony_ci "A RING", 1678c2ecf20Sopenharmony_ci/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX", 1688c2ecf20Sopenharmony_ci "E OOMLAUT", 1698c2ecf20Sopenharmony_ci/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH", 1708c2ecf20Sopenharmony_ci "N TILDE", 1718c2ecf20Sopenharmony_ci/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT", 1728c2ecf20Sopenharmony_ci/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE", 1738c2ecf20Sopenharmony_ci "U CIRCUMFLEX", 1748c2ecf20Sopenharmony_ci/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave", 1758c2ecf20Sopenharmony_ci/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring", 1768c2ecf20Sopenharmony_ci/*230*/ "ae", "c cidella", "e grave", "e acute", 1778c2ecf20Sopenharmony_ci/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute", 1788c2ecf20Sopenharmony_ci "i circumflex", 1798c2ecf20Sopenharmony_ci/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute", 1808c2ecf20Sopenharmony_ci "o circumflex", 1818c2ecf20Sopenharmony_ci/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave", 1828c2ecf20Sopenharmony_ci "u acute", 1838c2ecf20Sopenharmony_ci/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut" 1848c2ecf20Sopenharmony_ci}; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/* array of 256 u_short (one for each character) 1878c2ecf20Sopenharmony_ci * initialized to default_chartab and user selectable via 1888c2ecf20Sopenharmony_ci * /sys/module/speakup/parameters/chartab 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ciu_short spk_chartab[256]; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic u_short default_chartab[256] = { 1938c2ecf20Sopenharmony_ci B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */ 1948c2ecf20Sopenharmony_ci B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */ 1958c2ecf20Sopenharmony_ci B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */ 1968c2ecf20Sopenharmony_ci B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */ 1978c2ecf20Sopenharmony_ci WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */ 1988c2ecf20Sopenharmony_ci PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */ 1998c2ecf20Sopenharmony_ci NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */ 2008c2ecf20Sopenharmony_ci NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */ 2018c2ecf20Sopenharmony_ci PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */ 2028c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */ 2038c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */ 2048c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */ 2058c2ecf20Sopenharmony_ci PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */ 2068c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */ 2078c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */ 2088c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */ 2098c2ecf20Sopenharmony_ci B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */ 2108c2ecf20Sopenharmony_ci B_SYM, /* 135 */ 2118c2ecf20Sopenharmony_ci B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */ 2128c2ecf20Sopenharmony_ci B_CAPSYM, /* 143 */ 2138c2ecf20Sopenharmony_ci B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */ 2148c2ecf20Sopenharmony_ci B_SYM, /* 151 */ 2158c2ecf20Sopenharmony_ci B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */ 2168c2ecf20Sopenharmony_ci B_SYM, /* 159 */ 2178c2ecf20Sopenharmony_ci WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */ 2188c2ecf20Sopenharmony_ci B_SYM, /* 167 */ 2198c2ecf20Sopenharmony_ci B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */ 2208c2ecf20Sopenharmony_ci B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */ 2218c2ecf20Sopenharmony_ci B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */ 2228c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */ 2238c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */ 2248c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */ 2258c2ecf20Sopenharmony_ci A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */ 2268c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */ 2278c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */ 2288c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */ 2298c2ecf20Sopenharmony_ci ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */ 2308c2ecf20Sopenharmony_ci}; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistruct task_struct *speakup_task; 2338c2ecf20Sopenharmony_cistruct bleep spk_unprocessed_sound; 2348c2ecf20Sopenharmony_cistatic int spk_keydown; 2358c2ecf20Sopenharmony_cistatic u16 spk_lastkey; 2368c2ecf20Sopenharmony_cistatic u_char spk_close_press, keymap_flags; 2378c2ecf20Sopenharmony_cistatic u_char last_keycode, this_speakup_key; 2388c2ecf20Sopenharmony_cistatic u_long last_spk_jiffy; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistruct st_spk_t *speakup_console[MAX_NR_CONSOLES]; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciDEFINE_MUTEX(spk_mutex); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic int keyboard_notifier_call(struct notifier_block *, 2458c2ecf20Sopenharmony_ci unsigned long code, void *param); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic struct notifier_block keyboard_notifier_block = { 2488c2ecf20Sopenharmony_ci .notifier_call = keyboard_notifier_call, 2498c2ecf20Sopenharmony_ci}; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int vt_notifier_call(struct notifier_block *, 2528c2ecf20Sopenharmony_ci unsigned long code, void *param); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct notifier_block vt_notifier_block = { 2558c2ecf20Sopenharmony_ci .notifier_call = vt_notifier_call, 2568c2ecf20Sopenharmony_ci}; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic unsigned char get_attributes(struct vc_data *vc, u16 *pos) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); 2618c2ecf20Sopenharmony_ci return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void speakup_date(struct vc_data *vc) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci spk_x = spk_cx = vc->state.x; 2678c2ecf20Sopenharmony_ci spk_y = spk_cy = vc->state.y; 2688c2ecf20Sopenharmony_ci spk_pos = spk_cp = vc->vc_pos; 2698c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 2708c2ecf20Sopenharmony_ci spk_attr = get_attributes(vc, (u_short *)spk_pos); 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void bleep(u_short val) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci static const short vals[] = { 2768c2ecf20Sopenharmony_ci 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659 2778c2ecf20Sopenharmony_ci }; 2788c2ecf20Sopenharmony_ci short freq; 2798c2ecf20Sopenharmony_ci int time = spk_bleep_time; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci freq = vals[val % 12]; 2828c2ecf20Sopenharmony_ci if (val > 11) 2838c2ecf20Sopenharmony_ci freq *= (1 << (val / 12)); 2848c2ecf20Sopenharmony_ci spk_unprocessed_sound.freq = freq; 2858c2ecf20Sopenharmony_ci spk_unprocessed_sound.jiffies = msecs_to_jiffies(time); 2868c2ecf20Sopenharmony_ci spk_unprocessed_sound.active = 1; 2878c2ecf20Sopenharmony_ci /* We can only have 1 active sound at a time. */ 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void speakup_shut_up(struct vc_data *vc) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci if (spk_killed) 2938c2ecf20Sopenharmony_ci return; 2948c2ecf20Sopenharmony_ci spk_shut_up |= 0x01; 2958c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 2968c2ecf20Sopenharmony_ci speakup_date(vc); 2978c2ecf20Sopenharmony_ci if (synth) 2988c2ecf20Sopenharmony_ci spk_do_flush(); 2998c2ecf20Sopenharmony_ci} 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_cistatic void speech_kill(struct vc_data *vc) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci char val = synth->is_alive(synth); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (val == 0) 3068c2ecf20Sopenharmony_ci return; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* re-enables synth, if disabled */ 3098c2ecf20Sopenharmony_ci if (val == 2 || spk_killed) { 3108c2ecf20Sopenharmony_ci /* dead */ 3118c2ecf20Sopenharmony_ci spk_shut_up &= ~0x40; 3128c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE)); 3138c2ecf20Sopenharmony_ci } else { 3148c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP)); 3158c2ecf20Sopenharmony_ci spk_shut_up |= 0x40; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_cistatic void speakup_off(struct vc_data *vc) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci if (spk_shut_up & 0x80) { 3228c2ecf20Sopenharmony_ci spk_shut_up &= 0x7f; 3238c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER)); 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci spk_shut_up |= 0x80; 3268c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF)); 3278c2ecf20Sopenharmony_ci } 3288c2ecf20Sopenharmony_ci speakup_date(vc); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void speakup_parked(struct vc_data *vc) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci if (spk_parked & 0x80) { 3348c2ecf20Sopenharmony_ci spk_parked = 0; 3358c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_UNPARKED)); 3368c2ecf20Sopenharmony_ci } else { 3378c2ecf20Sopenharmony_ci spk_parked |= 0x80; 3388c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_PARKED)); 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic void speakup_cut(struct vc_data *vc) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci static const char err_buf[] = "set selection failed"; 3458c2ecf20Sopenharmony_ci int ret; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci if (!mark_cut_flag) { 3488c2ecf20Sopenharmony_ci mark_cut_flag = 1; 3498c2ecf20Sopenharmony_ci spk_xs = (u_short)spk_x; 3508c2ecf20Sopenharmony_ci spk_ys = (u_short)spk_y; 3518c2ecf20Sopenharmony_ci spk_sel_cons = vc; 3528c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_MARK)); 3538c2ecf20Sopenharmony_ci return; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci spk_xe = (u_short)spk_x; 3568c2ecf20Sopenharmony_ci spk_ye = (u_short)spk_y; 3578c2ecf20Sopenharmony_ci mark_cut_flag = 0; 3588c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_CUT)); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci ret = speakup_set_selection(tty); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci switch (ret) { 3638c2ecf20Sopenharmony_ci case 0: 3648c2ecf20Sopenharmony_ci break; /* no error */ 3658c2ecf20Sopenharmony_ci case -EFAULT: 3668c2ecf20Sopenharmony_ci pr_warn("%sEFAULT\n", err_buf); 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case -EINVAL: 3698c2ecf20Sopenharmony_ci pr_warn("%sEINVAL\n", err_buf); 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci case -ENOMEM: 3728c2ecf20Sopenharmony_ci pr_warn("%sENOMEM\n", err_buf); 3738c2ecf20Sopenharmony_ci break; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic void speakup_paste(struct vc_data *vc) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci if (mark_cut_flag) { 3808c2ecf20Sopenharmony_ci mark_cut_flag = 0; 3818c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED)); 3828c2ecf20Sopenharmony_ci } else { 3838c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_PASTE)); 3848c2ecf20Sopenharmony_ci speakup_paste_selection(tty); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void say_attributes(struct vc_data *vc) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci int fg = spk_attr & 0x0f; 3918c2ecf20Sopenharmony_ci int bg = spk_attr >> 4; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci if (fg > 8) { 3948c2ecf20Sopenharmony_ci synth_printf("%s ", spk_msg_get(MSG_BRIGHT)); 3958c2ecf20Sopenharmony_ci fg -= 8; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg)); 3988c2ecf20Sopenharmony_ci if (bg > 7) { 3998c2ecf20Sopenharmony_ci synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING)); 4008c2ecf20Sopenharmony_ci bg -= 8; 4018c2ecf20Sopenharmony_ci } else { 4028c2ecf20Sopenharmony_ci synth_printf(" %s ", spk_msg_get(MSG_ON)); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg)); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cienum { 4088c2ecf20Sopenharmony_ci edge_top = 1, 4098c2ecf20Sopenharmony_ci edge_bottom, 4108c2ecf20Sopenharmony_ci edge_left, 4118c2ecf20Sopenharmony_ci edge_right, 4128c2ecf20Sopenharmony_ci edge_quiet 4138c2ecf20Sopenharmony_ci}; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void announce_edge(struct vc_data *vc, int msg_id) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci if (spk_bleeps & 1) 4188c2ecf20Sopenharmony_ci bleep(spk_y); 4198c2ecf20Sopenharmony_ci if ((spk_bleeps & 2) && (msg_id < edge_quiet)) 4208c2ecf20Sopenharmony_ci synth_printf("%s\n", 4218c2ecf20Sopenharmony_ci spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1)); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic void speak_char(u16 ch) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci char *cp; 4278c2ecf20Sopenharmony_ci struct var_t *direct = spk_get_var(DIRECT); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (ch >= 0x100 || (direct && direct->u.n.value)) { 4308c2ecf20Sopenharmony_ci if (ch < 0x100 && IS_CHAR(ch, B_CAP)) { 4318c2ecf20Sopenharmony_ci spk_pitch_shift++; 4328c2ecf20Sopenharmony_ci synth_printf("%s", spk_str_caps_start); 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci synth_putwc_s(ch); 4358c2ecf20Sopenharmony_ci if (ch < 0x100 && IS_CHAR(ch, B_CAP)) 4368c2ecf20Sopenharmony_ci synth_printf("%s", spk_str_caps_stop); 4378c2ecf20Sopenharmony_ci return; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci cp = spk_characters[ch]; 4418c2ecf20Sopenharmony_ci if (!cp) { 4428c2ecf20Sopenharmony_ci pr_info("%s: cp == NULL!\n", __func__); 4438c2ecf20Sopenharmony_ci return; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci if (IS_CHAR(ch, B_CAP)) { 4468c2ecf20Sopenharmony_ci spk_pitch_shift++; 4478c2ecf20Sopenharmony_ci synth_printf("%s %s %s", 4488c2ecf20Sopenharmony_ci spk_str_caps_start, cp, spk_str_caps_stop); 4498c2ecf20Sopenharmony_ci } else { 4508c2ecf20Sopenharmony_ci if (*cp == '^') { 4518c2ecf20Sopenharmony_ci cp++; 4528c2ecf20Sopenharmony_ci synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp); 4538c2ecf20Sopenharmony_ci } else { 4548c2ecf20Sopenharmony_ci synth_printf(" %s ", cp); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci u16 ch = ' '; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci if (vc && pos) { 4648c2ecf20Sopenharmony_ci u16 w; 4658c2ecf20Sopenharmony_ci u16 c; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true); 4688c2ecf20Sopenharmony_ci w = scr_readw(pos); 4698c2ecf20Sopenharmony_ci c = w & 0xff; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (w & vc->vc_hi_font_mask) { 4728c2ecf20Sopenharmony_ci w &= ~vc->vc_hi_font_mask; 4738c2ecf20Sopenharmony_ci c |= 0x100; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ch = inverse_translate(vc, c, 1); 4778c2ecf20Sopenharmony_ci *attribs = (w & 0xff00) >> 8; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return ch; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic void say_char(struct vc_data *vc) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci u16 ch; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 4878c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)spk_pos, &spk_attr); 4888c2ecf20Sopenharmony_ci if (spk_attr != spk_old_attr) { 4898c2ecf20Sopenharmony_ci if (spk_attrib_bleep & 1) 4908c2ecf20Sopenharmony_ci bleep(spk_y); 4918c2ecf20Sopenharmony_ci if (spk_attrib_bleep & 2) 4928c2ecf20Sopenharmony_ci say_attributes(vc); 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_ci speak_char(ch); 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_cistatic void say_phonetic_char(struct vc_data *vc) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci u16 ch; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 5028c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)spk_pos, &spk_attr); 5038c2ecf20Sopenharmony_ci if (ch <= 0x7f && isalpha(ch)) { 5048c2ecf20Sopenharmony_ci ch &= 0x1f; 5058c2ecf20Sopenharmony_ci synth_printf("%s\n", phonetic[--ch]); 5068c2ecf20Sopenharmony_ci } else { 5078c2ecf20Sopenharmony_ci if (ch < 0x100 && IS_CHAR(ch, B_NUM)) 5088c2ecf20Sopenharmony_ci synth_printf("%s ", spk_msg_get(MSG_NUMBER)); 5098c2ecf20Sopenharmony_ci speak_char(ch); 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic void say_prev_char(struct vc_data *vc) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci spk_parked |= 0x01; 5168c2ecf20Sopenharmony_ci if (spk_x == 0) { 5178c2ecf20Sopenharmony_ci announce_edge(vc, edge_left); 5188c2ecf20Sopenharmony_ci return; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci spk_x--; 5218c2ecf20Sopenharmony_ci spk_pos -= 2; 5228c2ecf20Sopenharmony_ci say_char(vc); 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_cistatic void say_next_char(struct vc_data *vc) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci spk_parked |= 0x01; 5288c2ecf20Sopenharmony_ci if (spk_x == vc->vc_cols - 1) { 5298c2ecf20Sopenharmony_ci announce_edge(vc, edge_right); 5308c2ecf20Sopenharmony_ci return; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci spk_x++; 5338c2ecf20Sopenharmony_ci spk_pos += 2; 5348c2ecf20Sopenharmony_ci say_char(vc); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci/* get_word - will first check to see if the character under the 5388c2ecf20Sopenharmony_ci * reading cursor is a space and if spk_say_word_ctl is true it will 5398c2ecf20Sopenharmony_ci * return the word space. If spk_say_word_ctl is not set it will check to 5408c2ecf20Sopenharmony_ci * see if there is a word starting on the next position to the right 5418c2ecf20Sopenharmony_ci * and return that word if it exists. If it does not exist it will 5428c2ecf20Sopenharmony_ci * move left to the beginning of any previous word on the line or the 5438c2ecf20Sopenharmony_ci * beginning off the line whichever comes first.. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic u_long get_word(struct vc_data *vc) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos; 5498c2ecf20Sopenharmony_ci u16 ch; 5508c2ecf20Sopenharmony_ci u16 attr_ch; 5518c2ecf20Sopenharmony_ci u_char temp; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 5548c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)tmp_pos, &temp); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci/* decided to take out the sayword if on a space (mis-information */ 5578c2ecf20Sopenharmony_ci if (spk_say_word_ctl && ch == SPACE) { 5588c2ecf20Sopenharmony_ci *buf = '\0'; 5598c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_SPACE)); 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci } else if (tmpx < vc->vc_cols - 2 && 5628c2ecf20Sopenharmony_ci (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) && 5638c2ecf20Sopenharmony_ci get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) { 5648c2ecf20Sopenharmony_ci tmp_pos += 2; 5658c2ecf20Sopenharmony_ci tmpx++; 5668c2ecf20Sopenharmony_ci } else { 5678c2ecf20Sopenharmony_ci while (tmpx > 0) { 5688c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)tmp_pos - 1, &temp); 5698c2ecf20Sopenharmony_ci if ((ch == SPACE || ch == 0 || 5708c2ecf20Sopenharmony_ci (ch < 0x100 && IS_WDLM(ch))) && 5718c2ecf20Sopenharmony_ci get_char(vc, (u_short *)tmp_pos, &temp) > SPACE) 5728c2ecf20Sopenharmony_ci break; 5738c2ecf20Sopenharmony_ci tmp_pos -= 2; 5748c2ecf20Sopenharmony_ci tmpx--; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr); 5788c2ecf20Sopenharmony_ci buf[cnt++] = attr_ch; 5798c2ecf20Sopenharmony_ci while (tmpx < vc->vc_cols - 1) { 5808c2ecf20Sopenharmony_ci tmp_pos += 2; 5818c2ecf20Sopenharmony_ci tmpx++; 5828c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)tmp_pos, &temp); 5838c2ecf20Sopenharmony_ci if (ch == SPACE || ch == 0 || 5848c2ecf20Sopenharmony_ci (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) && 5858c2ecf20Sopenharmony_ci ch > SPACE)) 5868c2ecf20Sopenharmony_ci break; 5878c2ecf20Sopenharmony_ci buf[cnt++] = ch; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci buf[cnt] = '\0'; 5908c2ecf20Sopenharmony_ci return cnt; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic void say_word(struct vc_data *vc) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci u_long cnt = get_word(vc); 5968c2ecf20Sopenharmony_ci u_short saved_punc_mask = spk_punc_mask; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci if (cnt == 0) 5998c2ecf20Sopenharmony_ci return; 6008c2ecf20Sopenharmony_ci spk_punc_mask = PUNC; 6018c2ecf20Sopenharmony_ci buf[cnt++] = SPACE; 6028c2ecf20Sopenharmony_ci spkup_write(buf, cnt); 6038c2ecf20Sopenharmony_ci spk_punc_mask = saved_punc_mask; 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic void say_prev_word(struct vc_data *vc) 6078c2ecf20Sopenharmony_ci{ 6088c2ecf20Sopenharmony_ci u_char temp; 6098c2ecf20Sopenharmony_ci u16 ch; 6108c2ecf20Sopenharmony_ci u_short edge_said = 0, last_state = 0, state = 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci spk_parked |= 0x01; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (spk_x == 0) { 6158c2ecf20Sopenharmony_ci if (spk_y == 0) { 6168c2ecf20Sopenharmony_ci announce_edge(vc, edge_top); 6178c2ecf20Sopenharmony_ci return; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci spk_y--; 6208c2ecf20Sopenharmony_ci spk_x = vc->vc_cols; 6218c2ecf20Sopenharmony_ci edge_said = edge_quiet; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci while (1) { 6248c2ecf20Sopenharmony_ci if (spk_x == 0) { 6258c2ecf20Sopenharmony_ci if (spk_y == 0) { 6268c2ecf20Sopenharmony_ci edge_said = edge_top; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci if (edge_said != edge_quiet) 6308c2ecf20Sopenharmony_ci edge_said = edge_left; 6318c2ecf20Sopenharmony_ci if (state > 0) 6328c2ecf20Sopenharmony_ci break; 6338c2ecf20Sopenharmony_ci spk_y--; 6348c2ecf20Sopenharmony_ci spk_x = vc->vc_cols - 1; 6358c2ecf20Sopenharmony_ci } else { 6368c2ecf20Sopenharmony_ci spk_x--; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci spk_pos -= 2; 6398c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)spk_pos, &temp); 6408c2ecf20Sopenharmony_ci if (ch == SPACE || ch == 0) 6418c2ecf20Sopenharmony_ci state = 0; 6428c2ecf20Sopenharmony_ci else if (ch < 0x100 && IS_WDLM(ch)) 6438c2ecf20Sopenharmony_ci state = 1; 6448c2ecf20Sopenharmony_ci else 6458c2ecf20Sopenharmony_ci state = 2; 6468c2ecf20Sopenharmony_ci if (state < last_state) { 6478c2ecf20Sopenharmony_ci spk_pos += 2; 6488c2ecf20Sopenharmony_ci spk_x++; 6498c2ecf20Sopenharmony_ci break; 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci last_state = state; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci if (spk_x == 0 && edge_said == edge_quiet) 6548c2ecf20Sopenharmony_ci edge_said = edge_left; 6558c2ecf20Sopenharmony_ci if (edge_said > 0 && edge_said < edge_quiet) 6568c2ecf20Sopenharmony_ci announce_edge(vc, edge_said); 6578c2ecf20Sopenharmony_ci say_word(vc); 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic void say_next_word(struct vc_data *vc) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci u_char temp; 6638c2ecf20Sopenharmony_ci u16 ch; 6648c2ecf20Sopenharmony_ci u_short edge_said = 0, last_state = 2, state = 0; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci spk_parked |= 0x01; 6678c2ecf20Sopenharmony_ci if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) { 6688c2ecf20Sopenharmony_ci announce_edge(vc, edge_bottom); 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci while (1) { 6728c2ecf20Sopenharmony_ci ch = get_char(vc, (u_short *)spk_pos, &temp); 6738c2ecf20Sopenharmony_ci if (ch == SPACE || ch == 0) 6748c2ecf20Sopenharmony_ci state = 0; 6758c2ecf20Sopenharmony_ci else if (ch < 0x100 && IS_WDLM(ch)) 6768c2ecf20Sopenharmony_ci state = 1; 6778c2ecf20Sopenharmony_ci else 6788c2ecf20Sopenharmony_ci state = 2; 6798c2ecf20Sopenharmony_ci if (state > last_state) 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci if (spk_x >= vc->vc_cols - 1) { 6828c2ecf20Sopenharmony_ci if (spk_y == vc->vc_rows - 1) { 6838c2ecf20Sopenharmony_ci edge_said = edge_bottom; 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci state = 0; 6878c2ecf20Sopenharmony_ci spk_y++; 6888c2ecf20Sopenharmony_ci spk_x = 0; 6898c2ecf20Sopenharmony_ci edge_said = edge_right; 6908c2ecf20Sopenharmony_ci } else { 6918c2ecf20Sopenharmony_ci spk_x++; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci spk_pos += 2; 6948c2ecf20Sopenharmony_ci last_state = state; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci if (edge_said > 0) 6978c2ecf20Sopenharmony_ci announce_edge(vc, edge_said); 6988c2ecf20Sopenharmony_ci say_word(vc); 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_cistatic void spell_word(struct vc_data *vc) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci static char const *delay_str[] = { "", ",", ".", ". .", ". . ." }; 7048c2ecf20Sopenharmony_ci u16 *cp = buf; 7058c2ecf20Sopenharmony_ci char *cp1; 7068c2ecf20Sopenharmony_ci char *str_cap = spk_str_caps_stop; 7078c2ecf20Sopenharmony_ci char *last_cap = spk_str_caps_stop; 7088c2ecf20Sopenharmony_ci struct var_t *direct = spk_get_var(DIRECT); 7098c2ecf20Sopenharmony_ci u16 ch; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (!get_word(vc)) 7128c2ecf20Sopenharmony_ci return; 7138c2ecf20Sopenharmony_ci while ((ch = *cp)) { 7148c2ecf20Sopenharmony_ci if (cp != buf) 7158c2ecf20Sopenharmony_ci synth_printf(" %s ", delay_str[spk_spell_delay]); 7168c2ecf20Sopenharmony_ci /* FIXME: Non-latin1 considered as lower case */ 7178c2ecf20Sopenharmony_ci if (ch < 0x100 && IS_CHAR(ch, B_CAP)) { 7188c2ecf20Sopenharmony_ci str_cap = spk_str_caps_start; 7198c2ecf20Sopenharmony_ci if (*spk_str_caps_stop) 7208c2ecf20Sopenharmony_ci spk_pitch_shift++; 7218c2ecf20Sopenharmony_ci else /* synth has no pitch */ 7228c2ecf20Sopenharmony_ci last_cap = spk_str_caps_stop; 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci str_cap = spk_str_caps_stop; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci if (str_cap != last_cap) { 7278c2ecf20Sopenharmony_ci synth_printf("%s", str_cap); 7288c2ecf20Sopenharmony_ci last_cap = str_cap; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci if (ch >= 0x100 || (direct && direct->u.n.value)) { 7318c2ecf20Sopenharmony_ci synth_putwc_s(ch); 7328c2ecf20Sopenharmony_ci } else if (this_speakup_key == SPELL_PHONETIC && 7338c2ecf20Sopenharmony_ci ch <= 0x7f && isalpha(ch)) { 7348c2ecf20Sopenharmony_ci ch &= 0x1f; 7358c2ecf20Sopenharmony_ci cp1 = phonetic[--ch]; 7368c2ecf20Sopenharmony_ci synth_printf("%s", cp1); 7378c2ecf20Sopenharmony_ci } else { 7388c2ecf20Sopenharmony_ci cp1 = spk_characters[ch]; 7398c2ecf20Sopenharmony_ci if (*cp1 == '^') { 7408c2ecf20Sopenharmony_ci synth_printf("%s", spk_msg_get(MSG_CTRL)); 7418c2ecf20Sopenharmony_ci cp1++; 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci synth_printf("%s", cp1); 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci cp++; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci if (str_cap != spk_str_caps_stop) 7488c2ecf20Sopenharmony_ci synth_printf("%s", spk_str_caps_stop); 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int get_line(struct vc_data *vc) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci u_long tmp = spk_pos - (spk_x * 2); 7548c2ecf20Sopenharmony_ci int i = 0; 7558c2ecf20Sopenharmony_ci u_char tmp2; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 7588c2ecf20Sopenharmony_ci spk_attr = get_attributes(vc, (u_short *)spk_pos); 7598c2ecf20Sopenharmony_ci for (i = 0; i < vc->vc_cols; i++) { 7608c2ecf20Sopenharmony_ci buf[i] = get_char(vc, (u_short *)tmp, &tmp2); 7618c2ecf20Sopenharmony_ci tmp += 2; 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci for (--i; i >= 0; i--) 7648c2ecf20Sopenharmony_ci if (buf[i] != SPACE) 7658c2ecf20Sopenharmony_ci break; 7668c2ecf20Sopenharmony_ci return ++i; 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_cistatic void say_line(struct vc_data *vc) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci int i = get_line(vc); 7728c2ecf20Sopenharmony_ci u16 *cp; 7738c2ecf20Sopenharmony_ci u_short saved_punc_mask = spk_punc_mask; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (i == 0) { 7768c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_BLANK)); 7778c2ecf20Sopenharmony_ci return; 7788c2ecf20Sopenharmony_ci } 7798c2ecf20Sopenharmony_ci buf[i++] = '\n'; 7808c2ecf20Sopenharmony_ci if (this_speakup_key == SAY_LINE_INDENT) { 7818c2ecf20Sopenharmony_ci cp = buf; 7828c2ecf20Sopenharmony_ci while (*cp == SPACE) 7838c2ecf20Sopenharmony_ci cp++; 7848c2ecf20Sopenharmony_ci synth_printf("%zd, ", (cp - buf) + 1); 7858c2ecf20Sopenharmony_ci } 7868c2ecf20Sopenharmony_ci spk_punc_mask = spk_punc_masks[spk_reading_punc]; 7878c2ecf20Sopenharmony_ci spkup_write(buf, i); 7888c2ecf20Sopenharmony_ci spk_punc_mask = saved_punc_mask; 7898c2ecf20Sopenharmony_ci} 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic void say_prev_line(struct vc_data *vc) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci spk_parked |= 0x01; 7948c2ecf20Sopenharmony_ci if (spk_y == 0) { 7958c2ecf20Sopenharmony_ci announce_edge(vc, edge_top); 7968c2ecf20Sopenharmony_ci return; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci spk_y--; 7998c2ecf20Sopenharmony_ci spk_pos -= vc->vc_size_row; 8008c2ecf20Sopenharmony_ci say_line(vc); 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic void say_next_line(struct vc_data *vc) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci spk_parked |= 0x01; 8068c2ecf20Sopenharmony_ci if (spk_y == vc->vc_rows - 1) { 8078c2ecf20Sopenharmony_ci announce_edge(vc, edge_bottom); 8088c2ecf20Sopenharmony_ci return; 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci spk_y++; 8118c2ecf20Sopenharmony_ci spk_pos += vc->vc_size_row; 8128c2ecf20Sopenharmony_ci say_line(vc); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic int say_from_to(struct vc_data *vc, u_long from, u_long to, 8168c2ecf20Sopenharmony_ci int read_punc) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci int i = 0; 8198c2ecf20Sopenharmony_ci u_char tmp; 8208c2ecf20Sopenharmony_ci u_short saved_punc_mask = spk_punc_mask; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 8238c2ecf20Sopenharmony_ci spk_attr = get_attributes(vc, (u_short *)from); 8248c2ecf20Sopenharmony_ci while (from < to) { 8258c2ecf20Sopenharmony_ci buf[i++] = get_char(vc, (u_short *)from, &tmp); 8268c2ecf20Sopenharmony_ci from += 2; 8278c2ecf20Sopenharmony_ci if (i >= vc->vc_size_row) 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci for (--i; i >= 0; i--) 8318c2ecf20Sopenharmony_ci if (buf[i] != SPACE) 8328c2ecf20Sopenharmony_ci break; 8338c2ecf20Sopenharmony_ci buf[++i] = SPACE; 8348c2ecf20Sopenharmony_ci buf[++i] = '\0'; 8358c2ecf20Sopenharmony_ci if (i < 1) 8368c2ecf20Sopenharmony_ci return i; 8378c2ecf20Sopenharmony_ci if (read_punc) 8388c2ecf20Sopenharmony_ci spk_punc_mask = spk_punc_info[spk_reading_punc].mask; 8398c2ecf20Sopenharmony_ci spkup_write(buf, i); 8408c2ecf20Sopenharmony_ci if (read_punc) 8418c2ecf20Sopenharmony_ci spk_punc_mask = saved_punc_mask; 8428c2ecf20Sopenharmony_ci return i - 1; 8438c2ecf20Sopenharmony_ci} 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_cistatic void say_line_from_to(struct vc_data *vc, u_long from, u_long to, 8468c2ecf20Sopenharmony_ci int read_punc) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci u_long start = vc->vc_origin + (spk_y * vc->vc_size_row); 8498c2ecf20Sopenharmony_ci u_long end = start + (to * 2); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci start += from * 2; 8528c2ecf20Sopenharmony_ci if (say_from_to(vc, start, end, read_punc) <= 0) 8538c2ecf20Sopenharmony_ci if (cursor_track != read_all_mode) 8548c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_BLANK)); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci/* Sentence Reading Commands */ 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic int currsentence; 8608c2ecf20Sopenharmony_cistatic int numsentences[2]; 8618c2ecf20Sopenharmony_cistatic u16 *sentbufend[2]; 8628c2ecf20Sopenharmony_cistatic u16 *sentmarks[2][10]; 8638c2ecf20Sopenharmony_cistatic int currbuf; 8648c2ecf20Sopenharmony_cistatic int bn; 8658c2ecf20Sopenharmony_cistatic u16 sentbuf[2][256]; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic int say_sentence_num(int num, int prev) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci bn = currbuf; 8708c2ecf20Sopenharmony_ci currsentence = num + 1; 8718c2ecf20Sopenharmony_ci if (prev && --bn == -1) 8728c2ecf20Sopenharmony_ci bn = 1; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (num > numsentences[bn]) 8758c2ecf20Sopenharmony_ci return 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]); 8788c2ecf20Sopenharmony_ci return 1; 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int get_sentence_buf(struct vc_data *vc, int read_punc) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci u_long start, end; 8848c2ecf20Sopenharmony_ci int i, bn; 8858c2ecf20Sopenharmony_ci u_char tmp; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci currbuf++; 8888c2ecf20Sopenharmony_ci if (currbuf == 2) 8898c2ecf20Sopenharmony_ci currbuf = 0; 8908c2ecf20Sopenharmony_ci bn = currbuf; 8918c2ecf20Sopenharmony_ci start = vc->vc_origin + ((spk_y) * vc->vc_size_row); 8928c2ecf20Sopenharmony_ci end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci numsentences[bn] = 0; 8958c2ecf20Sopenharmony_ci sentmarks[bn][0] = &sentbuf[bn][0]; 8968c2ecf20Sopenharmony_ci i = 0; 8978c2ecf20Sopenharmony_ci spk_old_attr = spk_attr; 8988c2ecf20Sopenharmony_ci spk_attr = get_attributes(vc, (u_short *)start); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci while (start < end) { 9018c2ecf20Sopenharmony_ci sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp); 9028c2ecf20Sopenharmony_ci if (i > 0) { 9038c2ecf20Sopenharmony_ci if (sentbuf[bn][i] == SPACE && 9048c2ecf20Sopenharmony_ci sentbuf[bn][i - 1] == '.' && 9058c2ecf20Sopenharmony_ci numsentences[bn] < 9) { 9068c2ecf20Sopenharmony_ci /* Sentence Marker */ 9078c2ecf20Sopenharmony_ci numsentences[bn]++; 9088c2ecf20Sopenharmony_ci sentmarks[bn][numsentences[bn]] = 9098c2ecf20Sopenharmony_ci &sentbuf[bn][i]; 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci i++; 9138c2ecf20Sopenharmony_ci start += 2; 9148c2ecf20Sopenharmony_ci if (i >= vc->vc_size_row) 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci } 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci for (--i; i >= 0; i--) 9198c2ecf20Sopenharmony_ci if (sentbuf[bn][i] != SPACE) 9208c2ecf20Sopenharmony_ci break; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (i < 1) 9238c2ecf20Sopenharmony_ci return -1; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci sentbuf[bn][++i] = SPACE; 9268c2ecf20Sopenharmony_ci sentbuf[bn][++i] = '\0'; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci sentbufend[bn] = &sentbuf[bn][i]; 9298c2ecf20Sopenharmony_ci return numsentences[bn]; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void say_screen_from_to(struct vc_data *vc, u_long from, u_long to) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci u_long start = vc->vc_origin, end; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (from > 0) 9378c2ecf20Sopenharmony_ci start += from * vc->vc_size_row; 9388c2ecf20Sopenharmony_ci if (to > vc->vc_rows) 9398c2ecf20Sopenharmony_ci to = vc->vc_rows; 9408c2ecf20Sopenharmony_ci end = vc->vc_origin + (to * vc->vc_size_row); 9418c2ecf20Sopenharmony_ci for (from = start; from < end; from = to) { 9428c2ecf20Sopenharmony_ci to = from + vc->vc_size_row; 9438c2ecf20Sopenharmony_ci say_from_to(vc, from, to, 1); 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic void say_screen(struct vc_data *vc) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci say_screen_from_to(vc, 0, vc->vc_rows); 9508c2ecf20Sopenharmony_ci} 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_cistatic void speakup_win_say(struct vc_data *vc) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci u_long start, end, from, to; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (win_start < 2) { 9578c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW)); 9588c2ecf20Sopenharmony_ci return; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci start = vc->vc_origin + (win_top * vc->vc_size_row); 9618c2ecf20Sopenharmony_ci end = vc->vc_origin + (win_bottom * vc->vc_size_row); 9628c2ecf20Sopenharmony_ci while (start <= end) { 9638c2ecf20Sopenharmony_ci from = start + (win_left * 2); 9648c2ecf20Sopenharmony_ci to = start + (win_right * 2); 9658c2ecf20Sopenharmony_ci say_from_to(vc, from, to, 1); 9668c2ecf20Sopenharmony_ci start += vc->vc_size_row; 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_cistatic void top_edge(struct vc_data *vc) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci spk_parked |= 0x01; 9738c2ecf20Sopenharmony_ci spk_pos = vc->vc_origin + 2 * spk_x; 9748c2ecf20Sopenharmony_ci spk_y = 0; 9758c2ecf20Sopenharmony_ci say_line(vc); 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistatic void bottom_edge(struct vc_data *vc) 9798c2ecf20Sopenharmony_ci{ 9808c2ecf20Sopenharmony_ci spk_parked |= 0x01; 9818c2ecf20Sopenharmony_ci spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row; 9828c2ecf20Sopenharmony_ci spk_y = vc->vc_rows - 1; 9838c2ecf20Sopenharmony_ci say_line(vc); 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic void left_edge(struct vc_data *vc) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci spk_parked |= 0x01; 9898c2ecf20Sopenharmony_ci spk_pos -= spk_x * 2; 9908c2ecf20Sopenharmony_ci spk_x = 0; 9918c2ecf20Sopenharmony_ci say_char(vc); 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_cistatic void right_edge(struct vc_data *vc) 9958c2ecf20Sopenharmony_ci{ 9968c2ecf20Sopenharmony_ci spk_parked |= 0x01; 9978c2ecf20Sopenharmony_ci spk_pos += (vc->vc_cols - spk_x - 1) * 2; 9988c2ecf20Sopenharmony_ci spk_x = vc->vc_cols - 1; 9998c2ecf20Sopenharmony_ci say_char(vc); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic void say_first_char(struct vc_data *vc) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci int i, len = get_line(vc); 10058c2ecf20Sopenharmony_ci u16 ch; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci spk_parked |= 0x01; 10088c2ecf20Sopenharmony_ci if (len == 0) { 10098c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_BLANK)); 10108c2ecf20Sopenharmony_ci return; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) 10138c2ecf20Sopenharmony_ci if (buf[i] != SPACE) 10148c2ecf20Sopenharmony_ci break; 10158c2ecf20Sopenharmony_ci ch = buf[i]; 10168c2ecf20Sopenharmony_ci spk_pos -= (spk_x - i) * 2; 10178c2ecf20Sopenharmony_ci spk_x = i; 10188c2ecf20Sopenharmony_ci synth_printf("%d, ", ++i); 10198c2ecf20Sopenharmony_ci speak_char(ch); 10208c2ecf20Sopenharmony_ci} 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic void say_last_char(struct vc_data *vc) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci int len = get_line(vc); 10258c2ecf20Sopenharmony_ci u16 ch; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci spk_parked |= 0x01; 10288c2ecf20Sopenharmony_ci if (len == 0) { 10298c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_BLANK)); 10308c2ecf20Sopenharmony_ci return; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci ch = buf[--len]; 10338c2ecf20Sopenharmony_ci spk_pos -= (spk_x - len) * 2; 10348c2ecf20Sopenharmony_ci spk_x = len; 10358c2ecf20Sopenharmony_ci synth_printf("%d, ", ++len); 10368c2ecf20Sopenharmony_ci speak_char(ch); 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic void say_position(struct vc_data *vc) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1, 10428c2ecf20Sopenharmony_ci vc->vc_num + 1); 10438c2ecf20Sopenharmony_ci synth_printf("\n"); 10448c2ecf20Sopenharmony_ci} 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci/* Added by brianb */ 10478c2ecf20Sopenharmony_cistatic void say_char_num(struct vc_data *vc) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci u_char tmp; 10508c2ecf20Sopenharmony_ci u16 ch = get_char(vc, (u_short *)spk_pos, &tmp); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch); 10538c2ecf20Sopenharmony_ci} 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci/* these are stub functions to keep keyboard.c happy. */ 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic void say_from_top(struct vc_data *vc) 10588c2ecf20Sopenharmony_ci{ 10598c2ecf20Sopenharmony_ci say_screen_from_to(vc, 0, spk_y); 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_cistatic void say_to_bottom(struct vc_data *vc) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci say_screen_from_to(vc, spk_y, vc->vc_rows); 10658c2ecf20Sopenharmony_ci} 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cistatic void say_from_left(struct vc_data *vc) 10688c2ecf20Sopenharmony_ci{ 10698c2ecf20Sopenharmony_ci say_line_from_to(vc, 0, spk_x, 1); 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic void say_to_right(struct vc_data *vc) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci say_line_from_to(vc, spk_x, vc->vc_cols, 1); 10758c2ecf20Sopenharmony_ci} 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci/* end of stub functions. */ 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic void spkup_write(const u16 *in_buf, int count) 10808c2ecf20Sopenharmony_ci{ 10818c2ecf20Sopenharmony_ci static int rep_count; 10828c2ecf20Sopenharmony_ci static u16 ch = '\0', old_ch = '\0'; 10838c2ecf20Sopenharmony_ci static u_short char_type, last_type; 10848c2ecf20Sopenharmony_ci int in_count = count; 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci spk_keydown = 0; 10878c2ecf20Sopenharmony_ci while (count--) { 10888c2ecf20Sopenharmony_ci if (cursor_track == read_all_mode) { 10898c2ecf20Sopenharmony_ci /* Insert Sentence Index */ 10908c2ecf20Sopenharmony_ci if ((in_buf == sentmarks[bn][currsentence]) && 10918c2ecf20Sopenharmony_ci (currsentence <= numsentences[bn])) 10928c2ecf20Sopenharmony_ci synth_insert_next_index(currsentence++); 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci ch = *in_buf++; 10958c2ecf20Sopenharmony_ci if (ch < 0x100) 10968c2ecf20Sopenharmony_ci char_type = spk_chartab[ch]; 10978c2ecf20Sopenharmony_ci else 10988c2ecf20Sopenharmony_ci char_type = ALPHA; 10998c2ecf20Sopenharmony_ci if (ch == old_ch && !(char_type & B_NUM)) { 11008c2ecf20Sopenharmony_ci if (++rep_count > 2) 11018c2ecf20Sopenharmony_ci continue; 11028c2ecf20Sopenharmony_ci } else { 11038c2ecf20Sopenharmony_ci if ((last_type & CH_RPT) && rep_count > 2) { 11048c2ecf20Sopenharmony_ci synth_printf(" "); 11058c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_REPEAT_DESC), 11068c2ecf20Sopenharmony_ci ++rep_count); 11078c2ecf20Sopenharmony_ci synth_printf(" "); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci rep_count = 0; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci if (ch == spk_lastkey) { 11128c2ecf20Sopenharmony_ci rep_count = 0; 11138c2ecf20Sopenharmony_ci if (spk_key_echo == 1 && ch >= MINECHOCHAR) 11148c2ecf20Sopenharmony_ci speak_char(ch); 11158c2ecf20Sopenharmony_ci } else if (char_type & B_ALPHA) { 11168c2ecf20Sopenharmony_ci if ((synth_flags & SF_DEC) && (last_type & PUNC)) 11178c2ecf20Sopenharmony_ci synth_buffer_add(SPACE); 11188c2ecf20Sopenharmony_ci synth_putwc_s(ch); 11198c2ecf20Sopenharmony_ci } else if (char_type & B_NUM) { 11208c2ecf20Sopenharmony_ci rep_count = 0; 11218c2ecf20Sopenharmony_ci synth_putwc_s(ch); 11228c2ecf20Sopenharmony_ci } else if (char_type & spk_punc_mask) { 11238c2ecf20Sopenharmony_ci speak_char(ch); 11248c2ecf20Sopenharmony_ci char_type &= ~PUNC; /* for dec nospell processing */ 11258c2ecf20Sopenharmony_ci } else if (char_type & SYNTH_OK) { 11268c2ecf20Sopenharmony_ci /* these are usually puncts like . and , which synth 11278c2ecf20Sopenharmony_ci * needs for expression. 11288c2ecf20Sopenharmony_ci * suppress multiple to get rid of long pauses and 11298c2ecf20Sopenharmony_ci * clear repeat count 11308c2ecf20Sopenharmony_ci * so if someone has 11318c2ecf20Sopenharmony_ci * repeats on you don't get nothing repeated count 11328c2ecf20Sopenharmony_ci */ 11338c2ecf20Sopenharmony_ci if (ch != old_ch) 11348c2ecf20Sopenharmony_ci synth_putwc_s(ch); 11358c2ecf20Sopenharmony_ci else 11368c2ecf20Sopenharmony_ci rep_count = 0; 11378c2ecf20Sopenharmony_ci } else { 11388c2ecf20Sopenharmony_ci/* send space and record position, if next is num overwrite space */ 11398c2ecf20Sopenharmony_ci if (old_ch != ch) 11408c2ecf20Sopenharmony_ci synth_buffer_add(SPACE); 11418c2ecf20Sopenharmony_ci else 11428c2ecf20Sopenharmony_ci rep_count = 0; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci old_ch = ch; 11458c2ecf20Sopenharmony_ci last_type = char_type; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci spk_lastkey = 0; 11488c2ecf20Sopenharmony_ci if (in_count > 2 && rep_count > 2) { 11498c2ecf20Sopenharmony_ci if (last_type & CH_RPT) { 11508c2ecf20Sopenharmony_ci synth_printf(" "); 11518c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_REPEAT_DESC2), 11528c2ecf20Sopenharmony_ci ++rep_count); 11538c2ecf20Sopenharmony_ci synth_printf(" "); 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci rep_count = 0; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_cistatic void read_all_doc(struct vc_data *vc); 11628c2ecf20Sopenharmony_cistatic void cursor_done(struct timer_list *unused); 11638c2ecf20Sopenharmony_cistatic DEFINE_TIMER(cursor_timer, cursor_done); 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic void do_handle_shift(struct vc_data *vc, u_char value, char up_flag) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci unsigned long flags; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (!synth || up_flag || spk_killed) 11708c2ecf20Sopenharmony_ci return; 11718c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 11728c2ecf20Sopenharmony_ci if (cursor_track == read_all_mode) { 11738c2ecf20Sopenharmony_ci switch (value) { 11748c2ecf20Sopenharmony_ci case KVAL(K_SHIFT): 11758c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 11768c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 11778c2ecf20Sopenharmony_ci spk_do_flush(); 11788c2ecf20Sopenharmony_ci read_all_doc(vc); 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci case KVAL(K_CTRL): 11818c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 11828c2ecf20Sopenharmony_ci cursor_track = prev_cursor_track; 11838c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 11848c2ecf20Sopenharmony_ci spk_do_flush(); 11858c2ecf20Sopenharmony_ci break; 11868c2ecf20Sopenharmony_ci } 11878c2ecf20Sopenharmony_ci } else { 11888c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 11898c2ecf20Sopenharmony_ci spk_do_flush(); 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci if (spk_say_ctrl && value < NUM_CTL_LABELS) 11928c2ecf20Sopenharmony_ci synth_printf("%s", spk_msg_get(MSG_CTL_START + value)); 11938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistatic void do_handle_latin(struct vc_data *vc, u_char value, char up_flag) 11978c2ecf20Sopenharmony_ci{ 11988c2ecf20Sopenharmony_ci unsigned long flags; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 12018c2ecf20Sopenharmony_ci if (up_flag) { 12028c2ecf20Sopenharmony_ci spk_lastkey = 0; 12038c2ecf20Sopenharmony_ci spk_keydown = 0; 12048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 12058c2ecf20Sopenharmony_ci return; 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci if (!synth || spk_killed) { 12088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 12098c2ecf20Sopenharmony_ci return; 12108c2ecf20Sopenharmony_ci } 12118c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 12128c2ecf20Sopenharmony_ci spk_lastkey = value; 12138c2ecf20Sopenharmony_ci spk_keydown++; 12148c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 12158c2ecf20Sopenharmony_ci if (spk_key_echo == 2 && value >= MINECHOCHAR) 12168c2ecf20Sopenharmony_ci speak_char(value); 12178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 12188c2ecf20Sopenharmony_ci} 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ciint spk_set_key_info(const u_char *key_info, u_char *k_buffer) 12218c2ecf20Sopenharmony_ci{ 12228c2ecf20Sopenharmony_ci int i = 0, states, key_data_len; 12238c2ecf20Sopenharmony_ci const u_char *cp = key_info; 12248c2ecf20Sopenharmony_ci u_char *cp1 = k_buffer; 12258c2ecf20Sopenharmony_ci u_char ch, version, num_keys; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci version = *cp++; 12288c2ecf20Sopenharmony_ci if (version != KEY_MAP_VER) { 12298c2ecf20Sopenharmony_ci pr_debug("version found %d should be %d\n", 12308c2ecf20Sopenharmony_ci version, KEY_MAP_VER); 12318c2ecf20Sopenharmony_ci return -EINVAL; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci num_keys = *cp; 12348c2ecf20Sopenharmony_ci states = (int)cp[1]; 12358c2ecf20Sopenharmony_ci key_data_len = (states + 1) * (num_keys + 1); 12368c2ecf20Sopenharmony_ci if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) { 12378c2ecf20Sopenharmony_ci pr_debug("too many key_infos (%d over %u)\n", 12388c2ecf20Sopenharmony_ci key_data_len + SHIFT_TBL_SIZE + 4, 12398c2ecf20Sopenharmony_ci (unsigned int)(sizeof(spk_key_buf))); 12408c2ecf20Sopenharmony_ci return -EINVAL; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci memset(k_buffer, 0, SHIFT_TBL_SIZE); 12438c2ecf20Sopenharmony_ci memset(spk_our_keys, 0, sizeof(spk_our_keys)); 12448c2ecf20Sopenharmony_ci spk_shift_table = k_buffer; 12458c2ecf20Sopenharmony_ci spk_our_keys[0] = spk_shift_table; 12468c2ecf20Sopenharmony_ci cp1 += SHIFT_TBL_SIZE; 12478c2ecf20Sopenharmony_ci memcpy(cp1, cp, key_data_len + 3); 12488c2ecf20Sopenharmony_ci /* get num_keys, states and data */ 12498c2ecf20Sopenharmony_ci cp1 += 2; /* now pointing at shift states */ 12508c2ecf20Sopenharmony_ci for (i = 1; i <= states; i++) { 12518c2ecf20Sopenharmony_ci ch = *cp1++; 12528c2ecf20Sopenharmony_ci if (ch >= SHIFT_TBL_SIZE) { 12538c2ecf20Sopenharmony_ci pr_debug("(%d) not valid shift state (max_allowed = %d)\n", 12548c2ecf20Sopenharmony_ci ch, SHIFT_TBL_SIZE); 12558c2ecf20Sopenharmony_ci return -EINVAL; 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci spk_shift_table[ch] = i; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci keymap_flags = *cp1++; 12608c2ecf20Sopenharmony_ci while ((ch = *cp1)) { 12618c2ecf20Sopenharmony_ci if (ch >= MAX_KEY) { 12628c2ecf20Sopenharmony_ci pr_debug("(%d), not valid key, (max_allowed = %d)\n", 12638c2ecf20Sopenharmony_ci ch, MAX_KEY); 12648c2ecf20Sopenharmony_ci return -EINVAL; 12658c2ecf20Sopenharmony_ci } 12668c2ecf20Sopenharmony_ci spk_our_keys[ch] = cp1; 12678c2ecf20Sopenharmony_ci cp1 += states + 1; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci return 0; 12708c2ecf20Sopenharmony_ci} 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cistatic struct var_t spk_vars[] = { 12738c2ecf20Sopenharmony_ci /* bell must be first to set high limit */ 12748c2ecf20Sopenharmony_ci {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} }, 12758c2ecf20Sopenharmony_ci {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} }, 12768c2ecf20Sopenharmony_ci {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} }, 12778c2ecf20Sopenharmony_ci {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} }, 12788c2ecf20Sopenharmony_ci {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} }, 12798c2ecf20Sopenharmony_ci {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} }, 12808c2ecf20Sopenharmony_ci {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} }, 12818c2ecf20Sopenharmony_ci {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} }, 12828c2ecf20Sopenharmony_ci {SAY_CONTROL, TOGGLE_0}, 12838c2ecf20Sopenharmony_ci {SAY_WORD_CTL, TOGGLE_0}, 12848c2ecf20Sopenharmony_ci {NO_INTERRUPT, TOGGLE_0}, 12858c2ecf20Sopenharmony_ci {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} }, 12868c2ecf20Sopenharmony_ci V_LAST_VAR 12878c2ecf20Sopenharmony_ci}; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic void toggle_cursoring(struct vc_data *vc) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci if (cursor_track == read_all_mode) 12928c2ecf20Sopenharmony_ci cursor_track = prev_cursor_track; 12938c2ecf20Sopenharmony_ci if (++cursor_track >= CT_Max) 12948c2ecf20Sopenharmony_ci cursor_track = 0; 12958c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track)); 12968c2ecf20Sopenharmony_ci} 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_civoid spk_reset_default_chars(void) 12998c2ecf20Sopenharmony_ci{ 13008c2ecf20Sopenharmony_ci int i; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci /* First, free any non-default */ 13038c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 13048c2ecf20Sopenharmony_ci if (spk_characters[i] && 13058c2ecf20Sopenharmony_ci (spk_characters[i] != spk_default_chars[i])) 13068c2ecf20Sopenharmony_ci kfree(spk_characters[i]); 13078c2ecf20Sopenharmony_ci } 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars)); 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_civoid spk_reset_default_chartab(void) 13138c2ecf20Sopenharmony_ci{ 13148c2ecf20Sopenharmony_ci memcpy(spk_chartab, default_chartab, sizeof(default_chartab)); 13158c2ecf20Sopenharmony_ci} 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_cistatic const struct st_bits_data *pb_edit; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_cistatic int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key) 13208c2ecf20Sopenharmony_ci{ 13218c2ecf20Sopenharmony_ci short mask = pb_edit->mask, ch_type = spk_chartab[ch]; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE) 13248c2ecf20Sopenharmony_ci return -1; 13258c2ecf20Sopenharmony_ci if (ch == SPACE) { 13268c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE)); 13278c2ecf20Sopenharmony_ci spk_special_handler = NULL; 13288c2ecf20Sopenharmony_ci return 1; 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci if (mask < PUNC && !(ch_type & PUNC)) 13318c2ecf20Sopenharmony_ci return -1; 13328c2ecf20Sopenharmony_ci spk_chartab[ch] ^= mask; 13338c2ecf20Sopenharmony_ci speak_char(ch); 13348c2ecf20Sopenharmony_ci synth_printf(" %s\n", 13358c2ecf20Sopenharmony_ci (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) : 13368c2ecf20Sopenharmony_ci spk_msg_get(MSG_OFF)); 13378c2ecf20Sopenharmony_ci return 1; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci/* Allocation concurrency is protected by the console semaphore */ 13418c2ecf20Sopenharmony_cistatic int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci int vc_num; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci vc_num = vc->vc_num; 13468c2ecf20Sopenharmony_ci if (!speakup_console[vc_num]) { 13478c2ecf20Sopenharmony_ci speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]), 13488c2ecf20Sopenharmony_ci gfp_flags); 13498c2ecf20Sopenharmony_ci if (!speakup_console[vc_num]) 13508c2ecf20Sopenharmony_ci return -ENOMEM; 13518c2ecf20Sopenharmony_ci speakup_date(vc); 13528c2ecf20Sopenharmony_ci } else if (!spk_parked) { 13538c2ecf20Sopenharmony_ci speakup_date(vc); 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci return 0; 13578c2ecf20Sopenharmony_ci} 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_cistatic void speakup_deallocate(struct vc_data *vc) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci int vc_num; 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci vc_num = vc->vc_num; 13648c2ecf20Sopenharmony_ci kfree(speakup_console[vc_num]); 13658c2ecf20Sopenharmony_ci speakup_console[vc_num] = NULL; 13668c2ecf20Sopenharmony_ci} 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_cistatic u_char is_cursor; 13698c2ecf20Sopenharmony_cistatic u_long old_cursor_pos, old_cursor_x, old_cursor_y; 13708c2ecf20Sopenharmony_cistatic int cursor_con; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_cistatic void reset_highlight_buffers(struct vc_data *); 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int read_all_key; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic int in_keyboard_notifier; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_cistatic void start_read_all_timer(struct vc_data *vc, int command); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_cienum { 13818c2ecf20Sopenharmony_ci RA_NOTHING, 13828c2ecf20Sopenharmony_ci RA_NEXT_SENT, 13838c2ecf20Sopenharmony_ci RA_PREV_LINE, 13848c2ecf20Sopenharmony_ci RA_NEXT_LINE, 13858c2ecf20Sopenharmony_ci RA_PREV_SENT, 13868c2ecf20Sopenharmony_ci RA_DOWN_ARROW, 13878c2ecf20Sopenharmony_ci RA_TIMER, 13888c2ecf20Sopenharmony_ci RA_FIND_NEXT_SENT, 13898c2ecf20Sopenharmony_ci RA_FIND_PREV_SENT, 13908c2ecf20Sopenharmony_ci}; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_cistatic void kbd_fakekey2(struct vc_data *vc, int command) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 13958c2ecf20Sopenharmony_ci speakup_fake_down_arrow(); 13968c2ecf20Sopenharmony_ci start_read_all_timer(vc, command); 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_cistatic void read_all_doc(struct vc_data *vc) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci if ((vc->vc_num != fg_console) || !synth || spk_shut_up) 14028c2ecf20Sopenharmony_ci return; 14038c2ecf20Sopenharmony_ci if (!synth_supports_indexing()) 14048c2ecf20Sopenharmony_ci return; 14058c2ecf20Sopenharmony_ci if (cursor_track != read_all_mode) 14068c2ecf20Sopenharmony_ci prev_cursor_track = cursor_track; 14078c2ecf20Sopenharmony_ci cursor_track = read_all_mode; 14088c2ecf20Sopenharmony_ci spk_reset_index_count(0); 14098c2ecf20Sopenharmony_ci if (get_sentence_buf(vc, 0) == -1) { 14108c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 14118c2ecf20Sopenharmony_ci if (!in_keyboard_notifier) 14128c2ecf20Sopenharmony_ci speakup_fake_down_arrow(); 14138c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_DOWN_ARROW); 14148c2ecf20Sopenharmony_ci } else { 14158c2ecf20Sopenharmony_ci say_sentence_num(0, 0); 14168c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14178c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_TIMER); 14188c2ecf20Sopenharmony_ci } 14198c2ecf20Sopenharmony_ci} 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_cistatic void stop_read_all(struct vc_data *vc) 14228c2ecf20Sopenharmony_ci{ 14238c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 14248c2ecf20Sopenharmony_ci cursor_track = prev_cursor_track; 14258c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 14268c2ecf20Sopenharmony_ci spk_do_flush(); 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic void start_read_all_timer(struct vc_data *vc, int command) 14308c2ecf20Sopenharmony_ci{ 14318c2ecf20Sopenharmony_ci struct var_t *cursor_timeout; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci cursor_con = vc->vc_num; 14348c2ecf20Sopenharmony_ci read_all_key = command; 14358c2ecf20Sopenharmony_ci cursor_timeout = spk_get_var(CURSOR_TIME); 14368c2ecf20Sopenharmony_ci mod_timer(&cursor_timer, 14378c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(cursor_timeout->u.n.value)); 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic void handle_cursor_read_all(struct vc_data *vc, int command) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci int indcount, sentcount, rv, sn; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci switch (command) { 14458c2ecf20Sopenharmony_ci case RA_NEXT_SENT: 14468c2ecf20Sopenharmony_ci /* Get Current Sentence */ 14478c2ecf20Sopenharmony_ci spk_get_index_count(&indcount, &sentcount); 14488c2ecf20Sopenharmony_ci /*printk("%d %d ", indcount, sentcount); */ 14498c2ecf20Sopenharmony_ci spk_reset_index_count(sentcount + 1); 14508c2ecf20Sopenharmony_ci if (indcount == 1) { 14518c2ecf20Sopenharmony_ci if (!say_sentence_num(sentcount + 1, 0)) { 14528c2ecf20Sopenharmony_ci kbd_fakekey2(vc, RA_FIND_NEXT_SENT); 14538c2ecf20Sopenharmony_ci return; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14568c2ecf20Sopenharmony_ci } else { 14578c2ecf20Sopenharmony_ci sn = 0; 14588c2ecf20Sopenharmony_ci if (!say_sentence_num(sentcount + 1, 1)) { 14598c2ecf20Sopenharmony_ci sn = 1; 14608c2ecf20Sopenharmony_ci spk_reset_index_count(sn); 14618c2ecf20Sopenharmony_ci } else { 14628c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci if (!say_sentence_num(sn, 0)) { 14658c2ecf20Sopenharmony_ci kbd_fakekey2(vc, RA_FIND_NEXT_SENT); 14668c2ecf20Sopenharmony_ci return; 14678c2ecf20Sopenharmony_ci } 14688c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_TIMER); 14718c2ecf20Sopenharmony_ci break; 14728c2ecf20Sopenharmony_ci case RA_PREV_SENT: 14738c2ecf20Sopenharmony_ci break; 14748c2ecf20Sopenharmony_ci case RA_NEXT_LINE: 14758c2ecf20Sopenharmony_ci read_all_doc(vc); 14768c2ecf20Sopenharmony_ci break; 14778c2ecf20Sopenharmony_ci case RA_PREV_LINE: 14788c2ecf20Sopenharmony_ci break; 14798c2ecf20Sopenharmony_ci case RA_DOWN_ARROW: 14808c2ecf20Sopenharmony_ci if (get_sentence_buf(vc, 0) == -1) { 14818c2ecf20Sopenharmony_ci kbd_fakekey2(vc, RA_DOWN_ARROW); 14828c2ecf20Sopenharmony_ci } else { 14838c2ecf20Sopenharmony_ci say_sentence_num(0, 0); 14848c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14858c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_TIMER); 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci break; 14888c2ecf20Sopenharmony_ci case RA_FIND_NEXT_SENT: 14898c2ecf20Sopenharmony_ci rv = get_sentence_buf(vc, 0); 14908c2ecf20Sopenharmony_ci if (rv == -1) 14918c2ecf20Sopenharmony_ci read_all_doc(vc); 14928c2ecf20Sopenharmony_ci if (rv == 0) { 14938c2ecf20Sopenharmony_ci kbd_fakekey2(vc, RA_FIND_NEXT_SENT); 14948c2ecf20Sopenharmony_ci } else { 14958c2ecf20Sopenharmony_ci say_sentence_num(1, 0); 14968c2ecf20Sopenharmony_ci synth_insert_next_index(0); 14978c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_TIMER); 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci break; 15008c2ecf20Sopenharmony_ci case RA_FIND_PREV_SENT: 15018c2ecf20Sopenharmony_ci break; 15028c2ecf20Sopenharmony_ci case RA_TIMER: 15038c2ecf20Sopenharmony_ci spk_get_index_count(&indcount, &sentcount); 15048c2ecf20Sopenharmony_ci if (indcount < 2) 15058c2ecf20Sopenharmony_ci kbd_fakekey2(vc, RA_DOWN_ARROW); 15068c2ecf20Sopenharmony_ci else 15078c2ecf20Sopenharmony_ci start_read_all_timer(vc, RA_TIMER); 15088c2ecf20Sopenharmony_ci break; 15098c2ecf20Sopenharmony_ci } 15108c2ecf20Sopenharmony_ci} 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci unsigned long flags; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 15178c2ecf20Sopenharmony_ci if (cursor_track == read_all_mode) { 15188c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 15198c2ecf20Sopenharmony_ci if (!synth || up_flag || spk_shut_up) { 15208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 15218c2ecf20Sopenharmony_ci return NOTIFY_STOP; 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 15248c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 15258c2ecf20Sopenharmony_ci spk_do_flush(); 15268c2ecf20Sopenharmony_ci start_read_all_timer(vc, value + 1); 15278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 15288c2ecf20Sopenharmony_ci return NOTIFY_STOP; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 15318c2ecf20Sopenharmony_ci return NOTIFY_OK; 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci unsigned long flags; 15378c2ecf20Sopenharmony_ci struct var_t *cursor_timeout; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 15408c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 15418c2ecf20Sopenharmony_ci if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) { 15428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 15438c2ecf20Sopenharmony_ci return; 15448c2ecf20Sopenharmony_ci } 15458c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 15468c2ecf20Sopenharmony_ci if (spk_no_intr) 15478c2ecf20Sopenharmony_ci spk_do_flush(); 15488c2ecf20Sopenharmony_ci/* the key press flushes if !no_inter but we want to flush on cursor 15498c2ecf20Sopenharmony_ci * moves regardless of no_inter state 15508c2ecf20Sopenharmony_ci */ 15518c2ecf20Sopenharmony_ci is_cursor = value + 1; 15528c2ecf20Sopenharmony_ci old_cursor_pos = vc->vc_pos; 15538c2ecf20Sopenharmony_ci old_cursor_x = vc->state.x; 15548c2ecf20Sopenharmony_ci old_cursor_y = vc->state.y; 15558c2ecf20Sopenharmony_ci speakup_console[vc->vc_num]->ht.cy = vc->state.y; 15568c2ecf20Sopenharmony_ci cursor_con = vc->vc_num; 15578c2ecf20Sopenharmony_ci if (cursor_track == CT_Highlight) 15588c2ecf20Sopenharmony_ci reset_highlight_buffers(vc); 15598c2ecf20Sopenharmony_ci cursor_timeout = spk_get_var(CURSOR_TIME); 15608c2ecf20Sopenharmony_ci mod_timer(&cursor_timer, 15618c2ecf20Sopenharmony_ci jiffies + msecs_to_jiffies(cursor_timeout->u.n.value)); 15628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 15638c2ecf20Sopenharmony_ci} 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_cistatic void update_color_buffer(struct vc_data *vc, const u16 *ic, int len) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci int i, bi, hi; 15688c2ecf20Sopenharmony_ci int vc_num = vc->vc_num; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci bi = (vc->vc_attr & 0x70) >> 4; 15718c2ecf20Sopenharmony_ci hi = speakup_console[vc_num]->ht.highsize[bi]; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci i = 0; 15748c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.highsize[bi] == 0) { 15758c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos; 15768c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.rx[bi] = vc->state.x; 15778c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.ry[bi] = vc->state.y; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci while ((hi < COLOR_BUFFER_SIZE) && (i < len)) { 15808c2ecf20Sopenharmony_ci if (ic[i] > 32) { 15818c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i]; 15828c2ecf20Sopenharmony_ci hi++; 15838c2ecf20Sopenharmony_ci } else if ((ic[i] == 32) && (hi != 0)) { 15848c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] != 15858c2ecf20Sopenharmony_ci 32) { 15868c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.highbuf[bi][hi] = 15878c2ecf20Sopenharmony_ci ic[i]; 15888c2ecf20Sopenharmony_ci hi++; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci i++; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.highsize[bi] = hi; 15948c2ecf20Sopenharmony_ci} 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_cistatic void reset_highlight_buffers(struct vc_data *vc) 15978c2ecf20Sopenharmony_ci{ 15988c2ecf20Sopenharmony_ci int i; 15998c2ecf20Sopenharmony_ci int vc_num = vc->vc_num; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16028c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.highsize[i] = 0; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic int count_highlight_color(struct vc_data *vc) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci int i, bg; 16088c2ecf20Sopenharmony_ci int cc; 16098c2ecf20Sopenharmony_ci int vc_num = vc->vc_num; 16108c2ecf20Sopenharmony_ci u16 ch; 16118c2ecf20Sopenharmony_ci u16 *start = (u16 *)vc->vc_origin; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16148c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.bgcount[i] = 0; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci for (i = 0; i < vc->vc_rows; i++) { 16178c2ecf20Sopenharmony_ci u16 *end = start + vc->vc_cols * 2; 16188c2ecf20Sopenharmony_ci u16 *ptr; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci for (ptr = start; ptr < end; ptr++) { 16218c2ecf20Sopenharmony_ci ch = get_attributes(vc, ptr); 16228c2ecf20Sopenharmony_ci bg = (ch & 0x70) >> 4; 16238c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.bgcount[bg]++; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci start += vc->vc_size_row; 16268c2ecf20Sopenharmony_ci } 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci cc = 0; 16298c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16308c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.bgcount[i] > 0) 16318c2ecf20Sopenharmony_ci cc++; 16328c2ecf20Sopenharmony_ci return cc; 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_cistatic int get_highlight_color(struct vc_data *vc) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci int i, j; 16388c2ecf20Sopenharmony_ci unsigned int cptr[8]; 16398c2ecf20Sopenharmony_ci int vc_num = vc->vc_num; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16428c2ecf20Sopenharmony_ci cptr[i] = i; 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) 16458c2ecf20Sopenharmony_ci for (j = i + 1; j < 8; j++) 16468c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.bgcount[cptr[i]] > 16478c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.bgcount[cptr[j]]) 16488c2ecf20Sopenharmony_ci swap(cptr[i], cptr[j]); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16518c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0) 16528c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0) 16538c2ecf20Sopenharmony_ci return cptr[i]; 16548c2ecf20Sopenharmony_ci return -1; 16558c2ecf20Sopenharmony_ci} 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_cistatic int speak_highlight(struct vc_data *vc) 16588c2ecf20Sopenharmony_ci{ 16598c2ecf20Sopenharmony_ci int hc, d; 16608c2ecf20Sopenharmony_ci int vc_num = vc->vc_num; 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci if (count_highlight_color(vc) == 1) 16638c2ecf20Sopenharmony_ci return 0; 16648c2ecf20Sopenharmony_ci hc = get_highlight_color(vc); 16658c2ecf20Sopenharmony_ci if (hc != -1) { 16668c2ecf20Sopenharmony_ci d = vc->state.y - speakup_console[vc_num]->ht.cy; 16678c2ecf20Sopenharmony_ci if ((d == 1) || (d == -1)) 16688c2ecf20Sopenharmony_ci if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y) 16698c2ecf20Sopenharmony_ci return 0; 16708c2ecf20Sopenharmony_ci spk_parked |= 0x01; 16718c2ecf20Sopenharmony_ci spk_do_flush(); 16728c2ecf20Sopenharmony_ci spkup_write(speakup_console[vc_num]->ht.highbuf[hc], 16738c2ecf20Sopenharmony_ci speakup_console[vc_num]->ht.highsize[hc]); 16748c2ecf20Sopenharmony_ci spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc]; 16758c2ecf20Sopenharmony_ci spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc]; 16768c2ecf20Sopenharmony_ci spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc]; 16778c2ecf20Sopenharmony_ci return 1; 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci return 0; 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_cistatic void cursor_done(struct timer_list *unused) 16838c2ecf20Sopenharmony_ci{ 16848c2ecf20Sopenharmony_ci struct vc_data *vc = vc_cons[cursor_con].d; 16858c2ecf20Sopenharmony_ci unsigned long flags; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 16888c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 16898c2ecf20Sopenharmony_ci if (cursor_con != fg_console) { 16908c2ecf20Sopenharmony_ci is_cursor = 0; 16918c2ecf20Sopenharmony_ci goto out; 16928c2ecf20Sopenharmony_ci } 16938c2ecf20Sopenharmony_ci speakup_date(vc); 16948c2ecf20Sopenharmony_ci if (win_enabled) { 16958c2ecf20Sopenharmony_ci if (vc->state.x >= win_left && vc->state.x <= win_right && 16968c2ecf20Sopenharmony_ci vc->state.y >= win_top && vc->state.y <= win_bottom) { 16978c2ecf20Sopenharmony_ci spk_keydown = 0; 16988c2ecf20Sopenharmony_ci is_cursor = 0; 16998c2ecf20Sopenharmony_ci goto out; 17008c2ecf20Sopenharmony_ci } 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci if (cursor_track == read_all_mode) { 17038c2ecf20Sopenharmony_ci handle_cursor_read_all(vc, read_all_key); 17048c2ecf20Sopenharmony_ci goto out; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci if (cursor_track == CT_Highlight) { 17078c2ecf20Sopenharmony_ci if (speak_highlight(vc)) { 17088c2ecf20Sopenharmony_ci spk_keydown = 0; 17098c2ecf20Sopenharmony_ci is_cursor = 0; 17108c2ecf20Sopenharmony_ci goto out; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci if (cursor_track == CT_Window) 17148c2ecf20Sopenharmony_ci speakup_win_say(vc); 17158c2ecf20Sopenharmony_ci else if (is_cursor == 1 || is_cursor == 4) 17168c2ecf20Sopenharmony_ci say_line_from_to(vc, 0, vc->vc_cols, 0); 17178c2ecf20Sopenharmony_ci else 17188c2ecf20Sopenharmony_ci say_char(vc); 17198c2ecf20Sopenharmony_ci spk_keydown = 0; 17208c2ecf20Sopenharmony_ci is_cursor = 0; 17218c2ecf20Sopenharmony_ciout: 17228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci/* called by: vt_notifier_call() */ 17268c2ecf20Sopenharmony_cistatic void speakup_bs(struct vc_data *vc) 17278c2ecf20Sopenharmony_ci{ 17288c2ecf20Sopenharmony_ci unsigned long flags; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (!speakup_console[vc->vc_num]) 17318c2ecf20Sopenharmony_ci return; 17328c2ecf20Sopenharmony_ci if (!spin_trylock_irqsave(&speakup_info.spinlock, flags)) 17338c2ecf20Sopenharmony_ci /* Speakup output, discard */ 17348c2ecf20Sopenharmony_ci return; 17358c2ecf20Sopenharmony_ci if (!spk_parked) 17368c2ecf20Sopenharmony_ci speakup_date(vc); 17378c2ecf20Sopenharmony_ci if (spk_shut_up || !synth) { 17388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17398c2ecf20Sopenharmony_ci return; 17408c2ecf20Sopenharmony_ci } 17418c2ecf20Sopenharmony_ci if (vc->vc_num == fg_console && spk_keydown) { 17428c2ecf20Sopenharmony_ci spk_keydown = 0; 17438c2ecf20Sopenharmony_ci if (!is_cursor) 17448c2ecf20Sopenharmony_ci say_char(vc); 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17478c2ecf20Sopenharmony_ci} 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci/* called by: vt_notifier_call() */ 17508c2ecf20Sopenharmony_cistatic void speakup_con_write(struct vc_data *vc, u16 *str, int len) 17518c2ecf20Sopenharmony_ci{ 17528c2ecf20Sopenharmony_ci unsigned long flags; 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci if ((vc->vc_num != fg_console) || spk_shut_up || !synth) 17558c2ecf20Sopenharmony_ci return; 17568c2ecf20Sopenharmony_ci if (!spin_trylock_irqsave(&speakup_info.spinlock, flags)) 17578c2ecf20Sopenharmony_ci /* Speakup output, discard */ 17588c2ecf20Sopenharmony_ci return; 17598c2ecf20Sopenharmony_ci if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1)) 17608c2ecf20Sopenharmony_ci bleep(3); 17618c2ecf20Sopenharmony_ci if ((is_cursor) || (cursor_track == read_all_mode)) { 17628c2ecf20Sopenharmony_ci if (cursor_track == CT_Highlight) 17638c2ecf20Sopenharmony_ci update_color_buffer(vc, str, len); 17648c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17658c2ecf20Sopenharmony_ci return; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci if (win_enabled) { 17688c2ecf20Sopenharmony_ci if (vc->state.x >= win_left && vc->state.x <= win_right && 17698c2ecf20Sopenharmony_ci vc->state.y >= win_top && vc->state.y <= win_bottom) { 17708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17718c2ecf20Sopenharmony_ci return; 17728c2ecf20Sopenharmony_ci } 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci spkup_write(str, len); 17768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17778c2ecf20Sopenharmony_ci} 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_cistatic void speakup_con_update(struct vc_data *vc) 17808c2ecf20Sopenharmony_ci{ 17818c2ecf20Sopenharmony_ci unsigned long flags; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (!speakup_console[vc->vc_num] || spk_parked || !synth) 17848c2ecf20Sopenharmony_ci return; 17858c2ecf20Sopenharmony_ci if (!spin_trylock_irqsave(&speakup_info.spinlock, flags)) 17868c2ecf20Sopenharmony_ci /* Speakup output, discard */ 17878c2ecf20Sopenharmony_ci return; 17888c2ecf20Sopenharmony_ci speakup_date(vc); 17898c2ecf20Sopenharmony_ci if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) { 17908c2ecf20Sopenharmony_ci synth_printf("%s", spk_str_pause); 17918c2ecf20Sopenharmony_ci spk_paused = true; 17928c2ecf20Sopenharmony_ci } 17938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 17948c2ecf20Sopenharmony_ci} 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_cistatic void do_handle_spec(struct vc_data *vc, u_char value, char up_flag) 17978c2ecf20Sopenharmony_ci{ 17988c2ecf20Sopenharmony_ci unsigned long flags; 17998c2ecf20Sopenharmony_ci int on_off = 2; 18008c2ecf20Sopenharmony_ci char *label; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci if (!synth || up_flag || spk_killed) 18038c2ecf20Sopenharmony_ci return; 18048c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 18058c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 18068c2ecf20Sopenharmony_ci if (spk_no_intr) 18078c2ecf20Sopenharmony_ci spk_do_flush(); 18088c2ecf20Sopenharmony_ci switch (value) { 18098c2ecf20Sopenharmony_ci case KVAL(K_CAPS): 18108c2ecf20Sopenharmony_ci label = spk_msg_get(MSG_KEYNAME_CAPSLOCK); 18118c2ecf20Sopenharmony_ci on_off = vt_get_leds(fg_console, VC_CAPSLOCK); 18128c2ecf20Sopenharmony_ci break; 18138c2ecf20Sopenharmony_ci case KVAL(K_NUM): 18148c2ecf20Sopenharmony_ci label = spk_msg_get(MSG_KEYNAME_NUMLOCK); 18158c2ecf20Sopenharmony_ci on_off = vt_get_leds(fg_console, VC_NUMLOCK); 18168c2ecf20Sopenharmony_ci break; 18178c2ecf20Sopenharmony_ci case KVAL(K_HOLD): 18188c2ecf20Sopenharmony_ci label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK); 18198c2ecf20Sopenharmony_ci on_off = vt_get_leds(fg_console, VC_SCROLLOCK); 18208c2ecf20Sopenharmony_ci if (speakup_console[vc->vc_num]) 18218c2ecf20Sopenharmony_ci speakup_console[vc->vc_num]->tty_stopped = on_off; 18228c2ecf20Sopenharmony_ci break; 18238c2ecf20Sopenharmony_ci default: 18248c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 18258c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 18268c2ecf20Sopenharmony_ci return; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci if (on_off < 2) 18298c2ecf20Sopenharmony_ci synth_printf("%s %s\n", 18308c2ecf20Sopenharmony_ci label, spk_msg_get(MSG_STATUS_START + on_off)); 18318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic int inc_dec_var(u_char value) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci struct st_var_header *p_header; 18378c2ecf20Sopenharmony_ci struct var_t *var_data; 18388c2ecf20Sopenharmony_ci char num_buf[32]; 18398c2ecf20Sopenharmony_ci char *cp = num_buf; 18408c2ecf20Sopenharmony_ci char *pn; 18418c2ecf20Sopenharmony_ci int var_id = (int)value - VAR_START; 18428c2ecf20Sopenharmony_ci int how = (var_id & 1) ? E_INC : E_DEC; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci var_id = var_id / 2 + FIRST_SET_VAR; 18458c2ecf20Sopenharmony_ci p_header = spk_get_var_header(var_id); 18468c2ecf20Sopenharmony_ci if (!p_header) 18478c2ecf20Sopenharmony_ci return -1; 18488c2ecf20Sopenharmony_ci if (p_header->var_type != VAR_NUM) 18498c2ecf20Sopenharmony_ci return -1; 18508c2ecf20Sopenharmony_ci var_data = p_header->data; 18518c2ecf20Sopenharmony_ci if (spk_set_num_var(1, p_header, how) != 0) 18528c2ecf20Sopenharmony_ci return -1; 18538c2ecf20Sopenharmony_ci if (!spk_close_press) { 18548c2ecf20Sopenharmony_ci for (pn = p_header->name; *pn; pn++) { 18558c2ecf20Sopenharmony_ci if (*pn == '_') 18568c2ecf20Sopenharmony_ci *cp = SPACE; 18578c2ecf20Sopenharmony_ci else 18588c2ecf20Sopenharmony_ci *cp++ = *pn; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ", 18628c2ecf20Sopenharmony_ci var_data->u.n.value); 18638c2ecf20Sopenharmony_ci synth_printf("%s", num_buf); 18648c2ecf20Sopenharmony_ci return 0; 18658c2ecf20Sopenharmony_ci} 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_cistatic void speakup_win_set(struct vc_data *vc) 18688c2ecf20Sopenharmony_ci{ 18698c2ecf20Sopenharmony_ci char info[40]; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci if (win_start > 1) { 18728c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET)); 18738c2ecf20Sopenharmony_ci return; 18748c2ecf20Sopenharmony_ci } 18758c2ecf20Sopenharmony_ci if (spk_x < win_left || spk_y < win_top) { 18768c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START)); 18778c2ecf20Sopenharmony_ci return; 18788c2ecf20Sopenharmony_ci } 18798c2ecf20Sopenharmony_ci if (win_start && spk_x == win_left && spk_y == win_top) { 18808c2ecf20Sopenharmony_ci win_left = 0; 18818c2ecf20Sopenharmony_ci win_right = vc->vc_cols - 1; 18828c2ecf20Sopenharmony_ci win_bottom = spk_y; 18838c2ecf20Sopenharmony_ci snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE), 18848c2ecf20Sopenharmony_ci (int)win_top + 1); 18858c2ecf20Sopenharmony_ci } else { 18868c2ecf20Sopenharmony_ci if (!win_start) { 18878c2ecf20Sopenharmony_ci win_top = spk_y; 18888c2ecf20Sopenharmony_ci win_left = spk_x; 18898c2ecf20Sopenharmony_ci } else { 18908c2ecf20Sopenharmony_ci win_bottom = spk_y; 18918c2ecf20Sopenharmony_ci win_right = spk_x; 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY), 18948c2ecf20Sopenharmony_ci (win_start) ? 18958c2ecf20Sopenharmony_ci spk_msg_get(MSG_END) : spk_msg_get(MSG_START), 18968c2ecf20Sopenharmony_ci (int)spk_y + 1, (int)spk_x + 1); 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci synth_printf("%s\n", info); 18998c2ecf20Sopenharmony_ci win_start++; 19008c2ecf20Sopenharmony_ci} 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_cistatic void speakup_win_clear(struct vc_data *vc) 19038c2ecf20Sopenharmony_ci{ 19048c2ecf20Sopenharmony_ci win_top = 0; 19058c2ecf20Sopenharmony_ci win_bottom = 0; 19068c2ecf20Sopenharmony_ci win_left = 0; 19078c2ecf20Sopenharmony_ci win_right = 0; 19088c2ecf20Sopenharmony_ci win_start = 0; 19098c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED)); 19108c2ecf20Sopenharmony_ci} 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_cistatic void speakup_win_enable(struct vc_data *vc) 19138c2ecf20Sopenharmony_ci{ 19148c2ecf20Sopenharmony_ci if (win_start < 2) { 19158c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW)); 19168c2ecf20Sopenharmony_ci return; 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci win_enabled ^= 1; 19198c2ecf20Sopenharmony_ci if (win_enabled) 19208c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED)); 19218c2ecf20Sopenharmony_ci else 19228c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED)); 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic void speakup_bits(struct vc_data *vc) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci int val = this_speakup_key - (FIRST_EDIT_BITS - 1); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci if (spk_special_handler || val < 1 || val > 6) { 19308c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_ERROR)); 19318c2ecf20Sopenharmony_ci return; 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci pb_edit = &spk_punc_info[val]; 19348c2ecf20Sopenharmony_ci synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name); 19358c2ecf20Sopenharmony_ci spk_special_handler = edit_bits; 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci static u_char goto_buf[8]; 19418c2ecf20Sopenharmony_ci static int num; 19428c2ecf20Sopenharmony_ci int maxlen; 19438c2ecf20Sopenharmony_ci char *cp; 19448c2ecf20Sopenharmony_ci u16 wch; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci if (type == KT_SPKUP && ch == SPEAKUP_GOTO) 19478c2ecf20Sopenharmony_ci goto do_goto; 19488c2ecf20Sopenharmony_ci if (type == KT_LATIN && ch == '\n') 19498c2ecf20Sopenharmony_ci goto do_goto; 19508c2ecf20Sopenharmony_ci if (type != 0) 19518c2ecf20Sopenharmony_ci goto oops; 19528c2ecf20Sopenharmony_ci if (ch == 8) { 19538c2ecf20Sopenharmony_ci u16 wch; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci if (num == 0) 19568c2ecf20Sopenharmony_ci return -1; 19578c2ecf20Sopenharmony_ci wch = goto_buf[--num]; 19588c2ecf20Sopenharmony_ci goto_buf[num] = '\0'; 19598c2ecf20Sopenharmony_ci spkup_write(&wch, 1); 19608c2ecf20Sopenharmony_ci return 1; 19618c2ecf20Sopenharmony_ci } 19628c2ecf20Sopenharmony_ci if (ch < '+' || ch > 'y') 19638c2ecf20Sopenharmony_ci goto oops; 19648c2ecf20Sopenharmony_ci wch = ch; 19658c2ecf20Sopenharmony_ci goto_buf[num++] = ch; 19668c2ecf20Sopenharmony_ci goto_buf[num] = '\0'; 19678c2ecf20Sopenharmony_ci spkup_write(&wch, 1); 19688c2ecf20Sopenharmony_ci maxlen = (*goto_buf >= '0') ? 3 : 4; 19698c2ecf20Sopenharmony_ci if ((ch == '+' || ch == '-') && num == 1) 19708c2ecf20Sopenharmony_ci return 1; 19718c2ecf20Sopenharmony_ci if (ch >= '0' && ch <= '9' && num < maxlen) 19728c2ecf20Sopenharmony_ci return 1; 19738c2ecf20Sopenharmony_ci if (num < maxlen - 1 || num > maxlen) 19748c2ecf20Sopenharmony_ci goto oops; 19758c2ecf20Sopenharmony_ci if (ch < 'x' || ch > 'y') { 19768c2ecf20Sopenharmony_cioops: 19778c2ecf20Sopenharmony_ci if (!spk_killed) 19788c2ecf20Sopenharmony_ci synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED)); 19798c2ecf20Sopenharmony_ci goto_buf[num = 0] = '\0'; 19808c2ecf20Sopenharmony_ci spk_special_handler = NULL; 19818c2ecf20Sopenharmony_ci return 1; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* Do not replace with kstrtoul: here we need cp to be updated */ 19858c2ecf20Sopenharmony_ci goto_pos = simple_strtoul(goto_buf, &cp, 10); 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if (*cp == 'x') { 19888c2ecf20Sopenharmony_ci if (*goto_buf < '0') 19898c2ecf20Sopenharmony_ci goto_pos += spk_x; 19908c2ecf20Sopenharmony_ci else if (goto_pos > 0) 19918c2ecf20Sopenharmony_ci goto_pos--; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci if (goto_pos >= vc->vc_cols) 19948c2ecf20Sopenharmony_ci goto_pos = vc->vc_cols - 1; 19958c2ecf20Sopenharmony_ci goto_x = 1; 19968c2ecf20Sopenharmony_ci } else { 19978c2ecf20Sopenharmony_ci if (*goto_buf < '0') 19988c2ecf20Sopenharmony_ci goto_pos += spk_y; 19998c2ecf20Sopenharmony_ci else if (goto_pos > 0) 20008c2ecf20Sopenharmony_ci goto_pos--; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (goto_pos >= vc->vc_rows) 20038c2ecf20Sopenharmony_ci goto_pos = vc->vc_rows - 1; 20048c2ecf20Sopenharmony_ci goto_x = 0; 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci goto_buf[num = 0] = '\0'; 20078c2ecf20Sopenharmony_cido_goto: 20088c2ecf20Sopenharmony_ci spk_special_handler = NULL; 20098c2ecf20Sopenharmony_ci spk_parked |= 0x01; 20108c2ecf20Sopenharmony_ci if (goto_x) { 20118c2ecf20Sopenharmony_ci spk_pos -= spk_x * 2; 20128c2ecf20Sopenharmony_ci spk_x = goto_pos; 20138c2ecf20Sopenharmony_ci spk_pos += goto_pos * 2; 20148c2ecf20Sopenharmony_ci say_word(vc); 20158c2ecf20Sopenharmony_ci } else { 20168c2ecf20Sopenharmony_ci spk_y = goto_pos; 20178c2ecf20Sopenharmony_ci spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row); 20188c2ecf20Sopenharmony_ci say_line(vc); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci return 1; 20218c2ecf20Sopenharmony_ci} 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_cistatic void speakup_goto(struct vc_data *vc) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci if (spk_special_handler) { 20268c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_ERROR)); 20278c2ecf20Sopenharmony_ci return; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci synth_printf("%s\n", spk_msg_get(MSG_GOTO)); 20308c2ecf20Sopenharmony_ci spk_special_handler = handle_goto; 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic void speakup_help(struct vc_data *vc) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0); 20368c2ecf20Sopenharmony_ci} 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_cistatic void do_nothing(struct vc_data *vc) 20398c2ecf20Sopenharmony_ci{ 20408c2ecf20Sopenharmony_ci return; /* flush done in do_spkup */ 20418c2ecf20Sopenharmony_ci} 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_cistatic u_char key_speakup, spk_key_locked; 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_cistatic void speakup_lock(struct vc_data *vc) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci if (!spk_key_locked) { 20488c2ecf20Sopenharmony_ci spk_key_locked = 16; 20498c2ecf20Sopenharmony_ci key_speakup = 16; 20508c2ecf20Sopenharmony_ci } else { 20518c2ecf20Sopenharmony_ci spk_key_locked = 0; 20528c2ecf20Sopenharmony_ci key_speakup = 0; 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_citypedef void (*spkup_hand) (struct vc_data *); 20578c2ecf20Sopenharmony_cistatic spkup_hand spkup_handler[] = { 20588c2ecf20Sopenharmony_ci /* must be ordered same as defines in speakup.h */ 20598c2ecf20Sopenharmony_ci do_nothing, speakup_goto, speech_kill, speakup_shut_up, 20608c2ecf20Sopenharmony_ci speakup_cut, speakup_paste, say_first_char, say_last_char, 20618c2ecf20Sopenharmony_ci say_char, say_prev_char, say_next_char, 20628c2ecf20Sopenharmony_ci say_word, say_prev_word, say_next_word, 20638c2ecf20Sopenharmony_ci say_line, say_prev_line, say_next_line, 20648c2ecf20Sopenharmony_ci top_edge, bottom_edge, left_edge, right_edge, 20658c2ecf20Sopenharmony_ci spell_word, spell_word, say_screen, 20668c2ecf20Sopenharmony_ci say_position, say_attributes, 20678c2ecf20Sopenharmony_ci speakup_off, speakup_parked, say_line, /* this is for indent */ 20688c2ecf20Sopenharmony_ci say_from_top, say_to_bottom, 20698c2ecf20Sopenharmony_ci say_from_left, say_to_right, 20708c2ecf20Sopenharmony_ci say_char_num, speakup_bits, speakup_bits, say_phonetic_char, 20718c2ecf20Sopenharmony_ci speakup_bits, speakup_bits, speakup_bits, 20728c2ecf20Sopenharmony_ci speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say, 20738c2ecf20Sopenharmony_ci speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL 20748c2ecf20Sopenharmony_ci}; 20758c2ecf20Sopenharmony_ci 20768c2ecf20Sopenharmony_cistatic void do_spkup(struct vc_data *vc, u_char value) 20778c2ecf20Sopenharmony_ci{ 20788c2ecf20Sopenharmony_ci if (spk_killed && value != SPEECH_KILL) 20798c2ecf20Sopenharmony_ci return; 20808c2ecf20Sopenharmony_ci spk_keydown = 0; 20818c2ecf20Sopenharmony_ci spk_lastkey = 0; 20828c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 20838c2ecf20Sopenharmony_ci this_speakup_key = value; 20848c2ecf20Sopenharmony_ci if (value < SPKUP_MAX_FUNC && spkup_handler[value]) { 20858c2ecf20Sopenharmony_ci spk_do_flush(); 20868c2ecf20Sopenharmony_ci (*spkup_handler[value]) (vc); 20878c2ecf20Sopenharmony_ci } else { 20888c2ecf20Sopenharmony_ci if (inc_dec_var(value) < 0) 20898c2ecf20Sopenharmony_ci bleep(9); 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_cistatic const char *pad_chars = "0123456789+-*/\015,.?()"; 20948c2ecf20Sopenharmony_ci 20958c2ecf20Sopenharmony_cistatic int 20968c2ecf20Sopenharmony_cispeakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym, 20978c2ecf20Sopenharmony_ci int up_flag) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci unsigned long flags; 21008c2ecf20Sopenharmony_ci int kh; 21018c2ecf20Sopenharmony_ci u_char *key_info; 21028c2ecf20Sopenharmony_ci u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0; 21038c2ecf20Sopenharmony_ci u_char shift_info, offset; 21048c2ecf20Sopenharmony_ci int ret = 0; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci if (!synth) 21078c2ecf20Sopenharmony_ci return 0; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci spin_lock_irqsave(&speakup_info.spinlock, flags); 21108c2ecf20Sopenharmony_ci tty = vc->port.tty; 21118c2ecf20Sopenharmony_ci if (type >= 0xf0) 21128c2ecf20Sopenharmony_ci type -= 0xf0; 21138c2ecf20Sopenharmony_ci if (type == KT_PAD && 21148c2ecf20Sopenharmony_ci (vt_get_leds(fg_console, VC_NUMLOCK))) { 21158c2ecf20Sopenharmony_ci if (up_flag) { 21168c2ecf20Sopenharmony_ci spk_keydown = 0; 21178c2ecf20Sopenharmony_ci goto out; 21188c2ecf20Sopenharmony_ci } 21198c2ecf20Sopenharmony_ci value = pad_chars[value]; 21208c2ecf20Sopenharmony_ci spk_lastkey = value; 21218c2ecf20Sopenharmony_ci spk_keydown++; 21228c2ecf20Sopenharmony_ci spk_parked &= 0xfe; 21238c2ecf20Sopenharmony_ci goto no_map; 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci if (keycode >= MAX_KEY) 21268c2ecf20Sopenharmony_ci goto no_map; 21278c2ecf20Sopenharmony_ci key_info = spk_our_keys[keycode]; 21288c2ecf20Sopenharmony_ci if (!key_info) 21298c2ecf20Sopenharmony_ci goto no_map; 21308c2ecf20Sopenharmony_ci /* Check valid read all mode keys */ 21318c2ecf20Sopenharmony_ci if ((cursor_track == read_all_mode) && (!up_flag)) { 21328c2ecf20Sopenharmony_ci switch (value) { 21338c2ecf20Sopenharmony_ci case KVAL(K_DOWN): 21348c2ecf20Sopenharmony_ci case KVAL(K_UP): 21358c2ecf20Sopenharmony_ci case KVAL(K_LEFT): 21368c2ecf20Sopenharmony_ci case KVAL(K_RIGHT): 21378c2ecf20Sopenharmony_ci case KVAL(K_PGUP): 21388c2ecf20Sopenharmony_ci case KVAL(K_PGDN): 21398c2ecf20Sopenharmony_ci break; 21408c2ecf20Sopenharmony_ci default: 21418c2ecf20Sopenharmony_ci stop_read_all(vc); 21428c2ecf20Sopenharmony_ci break; 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci } 21458c2ecf20Sopenharmony_ci shift_info = (shift_state & 0x0f) + key_speakup; 21468c2ecf20Sopenharmony_ci offset = spk_shift_table[shift_info]; 21478c2ecf20Sopenharmony_ci if (offset) { 21488c2ecf20Sopenharmony_ci new_key = key_info[offset]; 21498c2ecf20Sopenharmony_ci if (new_key) { 21508c2ecf20Sopenharmony_ci ret = 1; 21518c2ecf20Sopenharmony_ci if (new_key == SPK_KEY) { 21528c2ecf20Sopenharmony_ci if (!spk_key_locked) 21538c2ecf20Sopenharmony_ci key_speakup = (up_flag) ? 0 : 16; 21548c2ecf20Sopenharmony_ci if (up_flag || spk_killed) 21558c2ecf20Sopenharmony_ci goto out; 21568c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 21578c2ecf20Sopenharmony_ci spk_do_flush(); 21588c2ecf20Sopenharmony_ci goto out; 21598c2ecf20Sopenharmony_ci } 21608c2ecf20Sopenharmony_ci if (up_flag) 21618c2ecf20Sopenharmony_ci goto out; 21628c2ecf20Sopenharmony_ci if (last_keycode == keycode && 21638c2ecf20Sopenharmony_ci time_after(last_spk_jiffy + MAX_DELAY, jiffies)) { 21648c2ecf20Sopenharmony_ci spk_close_press = 1; 21658c2ecf20Sopenharmony_ci offset = spk_shift_table[shift_info + 32]; 21668c2ecf20Sopenharmony_ci /* double press? */ 21678c2ecf20Sopenharmony_ci if (offset && key_info[offset]) 21688c2ecf20Sopenharmony_ci new_key = key_info[offset]; 21698c2ecf20Sopenharmony_ci } 21708c2ecf20Sopenharmony_ci last_keycode = keycode; 21718c2ecf20Sopenharmony_ci last_spk_jiffy = jiffies; 21728c2ecf20Sopenharmony_ci type = KT_SPKUP; 21738c2ecf20Sopenharmony_ci value = new_key; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_cino_map: 21778c2ecf20Sopenharmony_ci if (type == KT_SPKUP && !spk_special_handler) { 21788c2ecf20Sopenharmony_ci do_spkup(vc, new_key); 21798c2ecf20Sopenharmony_ci spk_close_press = 0; 21808c2ecf20Sopenharmony_ci ret = 1; 21818c2ecf20Sopenharmony_ci goto out; 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_ci if (up_flag || spk_killed || type == KT_SHIFT) 21848c2ecf20Sopenharmony_ci goto out; 21858c2ecf20Sopenharmony_ci spk_shut_up &= 0xfe; 21868c2ecf20Sopenharmony_ci kh = (value == KVAL(K_DOWN)) || 21878c2ecf20Sopenharmony_ci (value == KVAL(K_UP)) || 21888c2ecf20Sopenharmony_ci (value == KVAL(K_LEFT)) || 21898c2ecf20Sopenharmony_ci (value == KVAL(K_RIGHT)); 21908c2ecf20Sopenharmony_ci if ((cursor_track != read_all_mode) || !kh) 21918c2ecf20Sopenharmony_ci if (!spk_no_intr) 21928c2ecf20Sopenharmony_ci spk_do_flush(); 21938c2ecf20Sopenharmony_ci if (spk_special_handler) { 21948c2ecf20Sopenharmony_ci if (type == KT_SPEC && value == 1) { 21958c2ecf20Sopenharmony_ci value = '\n'; 21968c2ecf20Sopenharmony_ci type = KT_LATIN; 21978c2ecf20Sopenharmony_ci } else if (type == KT_LETTER) { 21988c2ecf20Sopenharmony_ci type = KT_LATIN; 21998c2ecf20Sopenharmony_ci } else if (value == 0x7f) { 22008c2ecf20Sopenharmony_ci value = 8; /* make del = backspace */ 22018c2ecf20Sopenharmony_ci } 22028c2ecf20Sopenharmony_ci ret = (*spk_special_handler) (vc, type, value, keycode); 22038c2ecf20Sopenharmony_ci spk_close_press = 0; 22048c2ecf20Sopenharmony_ci if (ret < 0) 22058c2ecf20Sopenharmony_ci bleep(9); 22068c2ecf20Sopenharmony_ci goto out; 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci last_keycode = 0; 22098c2ecf20Sopenharmony_ciout: 22108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&speakup_info.spinlock, flags); 22118c2ecf20Sopenharmony_ci return ret; 22128c2ecf20Sopenharmony_ci} 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_cistatic int keyboard_notifier_call(struct notifier_block *nb, 22158c2ecf20Sopenharmony_ci unsigned long code, void *_param) 22168c2ecf20Sopenharmony_ci{ 22178c2ecf20Sopenharmony_ci struct keyboard_notifier_param *param = _param; 22188c2ecf20Sopenharmony_ci struct vc_data *vc = param->vc; 22198c2ecf20Sopenharmony_ci int up = !param->down; 22208c2ecf20Sopenharmony_ci int ret = NOTIFY_OK; 22218c2ecf20Sopenharmony_ci static int keycode; /* to hold the current keycode */ 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci in_keyboard_notifier = 1; 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci if (vc->vc_mode == KD_GRAPHICS) 22268c2ecf20Sopenharmony_ci goto out; 22278c2ecf20Sopenharmony_ci 22288c2ecf20Sopenharmony_ci /* 22298c2ecf20Sopenharmony_ci * First, determine whether we are handling a fake keypress on 22308c2ecf20Sopenharmony_ci * the current processor. If we are, then return NOTIFY_OK, 22318c2ecf20Sopenharmony_ci * to pass the keystroke up the chain. This prevents us from 22328c2ecf20Sopenharmony_ci * trying to take the Speakup lock while it is held by the 22338c2ecf20Sopenharmony_ci * processor on which the simulated keystroke was generated. 22348c2ecf20Sopenharmony_ci * Also, the simulated keystrokes should be ignored by Speakup. 22358c2ecf20Sopenharmony_ci */ 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci if (speakup_fake_key_pressed()) 22388c2ecf20Sopenharmony_ci goto out; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci switch (code) { 22418c2ecf20Sopenharmony_ci case KBD_KEYCODE: 22428c2ecf20Sopenharmony_ci /* speakup requires keycode and keysym currently */ 22438c2ecf20Sopenharmony_ci keycode = param->value; 22448c2ecf20Sopenharmony_ci break; 22458c2ecf20Sopenharmony_ci case KBD_UNBOUND_KEYCODE: 22468c2ecf20Sopenharmony_ci /* not used yet */ 22478c2ecf20Sopenharmony_ci break; 22488c2ecf20Sopenharmony_ci case KBD_UNICODE: 22498c2ecf20Sopenharmony_ci /* not used yet */ 22508c2ecf20Sopenharmony_ci break; 22518c2ecf20Sopenharmony_ci case KBD_KEYSYM: 22528c2ecf20Sopenharmony_ci if (speakup_key(vc, param->shift, keycode, param->value, up)) 22538c2ecf20Sopenharmony_ci ret = NOTIFY_STOP; 22548c2ecf20Sopenharmony_ci else if (KTYP(param->value) == KT_CUR) 22558c2ecf20Sopenharmony_ci ret = pre_handle_cursor(vc, KVAL(param->value), up); 22568c2ecf20Sopenharmony_ci break; 22578c2ecf20Sopenharmony_ci case KBD_POST_KEYSYM:{ 22588c2ecf20Sopenharmony_ci unsigned char type = KTYP(param->value) - 0xf0; 22598c2ecf20Sopenharmony_ci unsigned char val = KVAL(param->value); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci switch (type) { 22628c2ecf20Sopenharmony_ci case KT_SHIFT: 22638c2ecf20Sopenharmony_ci do_handle_shift(vc, val, up); 22648c2ecf20Sopenharmony_ci break; 22658c2ecf20Sopenharmony_ci case KT_LATIN: 22668c2ecf20Sopenharmony_ci case KT_LETTER: 22678c2ecf20Sopenharmony_ci do_handle_latin(vc, val, up); 22688c2ecf20Sopenharmony_ci break; 22698c2ecf20Sopenharmony_ci case KT_CUR: 22708c2ecf20Sopenharmony_ci do_handle_cursor(vc, val, up); 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci case KT_SPEC: 22738c2ecf20Sopenharmony_ci do_handle_spec(vc, val, up); 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci } 22768c2ecf20Sopenharmony_ci break; 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci } 22798c2ecf20Sopenharmony_ciout: 22808c2ecf20Sopenharmony_ci in_keyboard_notifier = 0; 22818c2ecf20Sopenharmony_ci return ret; 22828c2ecf20Sopenharmony_ci} 22838c2ecf20Sopenharmony_ci 22848c2ecf20Sopenharmony_cistatic int vt_notifier_call(struct notifier_block *nb, 22858c2ecf20Sopenharmony_ci unsigned long code, void *_param) 22868c2ecf20Sopenharmony_ci{ 22878c2ecf20Sopenharmony_ci struct vt_notifier_param *param = _param; 22888c2ecf20Sopenharmony_ci struct vc_data *vc = param->vc; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci switch (code) { 22918c2ecf20Sopenharmony_ci case VT_ALLOCATE: 22928c2ecf20Sopenharmony_ci if (vc->vc_mode == KD_TEXT) 22938c2ecf20Sopenharmony_ci speakup_allocate(vc, GFP_ATOMIC); 22948c2ecf20Sopenharmony_ci break; 22958c2ecf20Sopenharmony_ci case VT_DEALLOCATE: 22968c2ecf20Sopenharmony_ci speakup_deallocate(vc); 22978c2ecf20Sopenharmony_ci break; 22988c2ecf20Sopenharmony_ci case VT_WRITE: 22998c2ecf20Sopenharmony_ci if (param->c == '\b') { 23008c2ecf20Sopenharmony_ci speakup_bs(vc); 23018c2ecf20Sopenharmony_ci } else { 23028c2ecf20Sopenharmony_ci u16 d = param->c; 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci speakup_con_write(vc, &d, 1); 23058c2ecf20Sopenharmony_ci } 23068c2ecf20Sopenharmony_ci break; 23078c2ecf20Sopenharmony_ci case VT_UPDATE: 23088c2ecf20Sopenharmony_ci speakup_con_update(vc); 23098c2ecf20Sopenharmony_ci break; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci return NOTIFY_OK; 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci/* called by: module_exit() */ 23158c2ecf20Sopenharmony_cistatic void __exit speakup_exit(void) 23168c2ecf20Sopenharmony_ci{ 23178c2ecf20Sopenharmony_ci int i; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci unregister_keyboard_notifier(&keyboard_notifier_block); 23208c2ecf20Sopenharmony_ci unregister_vt_notifier(&vt_notifier_block); 23218c2ecf20Sopenharmony_ci speakup_unregister_devsynth(); 23228c2ecf20Sopenharmony_ci speakup_cancel_selection(); 23238c2ecf20Sopenharmony_ci speakup_cancel_paste(); 23248c2ecf20Sopenharmony_ci del_timer_sync(&cursor_timer); 23258c2ecf20Sopenharmony_ci kthread_stop(speakup_task); 23268c2ecf20Sopenharmony_ci speakup_task = NULL; 23278c2ecf20Sopenharmony_ci mutex_lock(&spk_mutex); 23288c2ecf20Sopenharmony_ci synth_release(); 23298c2ecf20Sopenharmony_ci mutex_unlock(&spk_mutex); 23308c2ecf20Sopenharmony_ci spk_ttyio_unregister_ldisc(); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci speakup_kobj_exit(); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 23358c2ecf20Sopenharmony_ci kfree(speakup_console[i]); 23368c2ecf20Sopenharmony_ci 23378c2ecf20Sopenharmony_ci speakup_remove_virtual_keyboard(); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci for (i = 0; i < MAXVARS; i++) 23408c2ecf20Sopenharmony_ci speakup_unregister_var(i); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 23438c2ecf20Sopenharmony_ci if (spk_characters[i] != spk_default_chars[i]) 23448c2ecf20Sopenharmony_ci kfree(spk_characters[i]); 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci spk_free_user_msgs(); 23488c2ecf20Sopenharmony_ci} 23498c2ecf20Sopenharmony_ci 23508c2ecf20Sopenharmony_ci/* call by: module_init() */ 23518c2ecf20Sopenharmony_cistatic int __init speakup_init(void) 23528c2ecf20Sopenharmony_ci{ 23538c2ecf20Sopenharmony_ci int i; 23548c2ecf20Sopenharmony_ci long err = 0; 23558c2ecf20Sopenharmony_ci struct vc_data *vc = vc_cons[fg_console].d; 23568c2ecf20Sopenharmony_ci struct var_t *var; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_ci /* These first few initializations cannot fail. */ 23598c2ecf20Sopenharmony_ci spk_initialize_msgs(); /* Initialize arrays for i18n. */ 23608c2ecf20Sopenharmony_ci spk_reset_default_chars(); 23618c2ecf20Sopenharmony_ci spk_reset_default_chartab(); 23628c2ecf20Sopenharmony_ci spk_strlwr(synth_name); 23638c2ecf20Sopenharmony_ci spk_vars[0].u.n.high = vc->vc_cols; 23648c2ecf20Sopenharmony_ci for (var = spk_vars; var->var_id != MAXVARS; var++) 23658c2ecf20Sopenharmony_ci speakup_register_var(var); 23668c2ecf20Sopenharmony_ci for (var = synth_time_vars; 23678c2ecf20Sopenharmony_ci (var->var_id >= 0) && (var->var_id < MAXVARS); var++) 23688c2ecf20Sopenharmony_ci speakup_register_var(var); 23698c2ecf20Sopenharmony_ci for (i = 1; spk_punc_info[i].mask != 0; i++) 23708c2ecf20Sopenharmony_ci spk_set_mask_bits(NULL, i, 2); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci spk_set_key_info(spk_key_defaults, spk_key_buf); 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci /* From here on out, initializations can fail. */ 23758c2ecf20Sopenharmony_ci err = speakup_add_virtual_keyboard(); 23768c2ecf20Sopenharmony_ci if (err) 23778c2ecf20Sopenharmony_ci goto error_virtkeyboard; 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 23808c2ecf20Sopenharmony_ci if (vc_cons[i].d) { 23818c2ecf20Sopenharmony_ci err = speakup_allocate(vc_cons[i].d, GFP_KERNEL); 23828c2ecf20Sopenharmony_ci if (err) 23838c2ecf20Sopenharmony_ci goto error_kobjects; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (spk_quiet_boot) 23878c2ecf20Sopenharmony_ci spk_shut_up |= 0x01; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci err = speakup_kobj_init(); 23908c2ecf20Sopenharmony_ci if (err) 23918c2ecf20Sopenharmony_ci goto error_kobjects; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci spk_ttyio_register_ldisc(); 23948c2ecf20Sopenharmony_ci synth_init(synth_name); 23958c2ecf20Sopenharmony_ci speakup_register_devsynth(); 23968c2ecf20Sopenharmony_ci /* 23978c2ecf20Sopenharmony_ci * register_devsynth might fail, but this error is not fatal. 23988c2ecf20Sopenharmony_ci * /dev/synth is an extra feature; the rest of Speakup 23998c2ecf20Sopenharmony_ci * will work fine without it. 24008c2ecf20Sopenharmony_ci */ 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci err = register_keyboard_notifier(&keyboard_notifier_block); 24038c2ecf20Sopenharmony_ci if (err) 24048c2ecf20Sopenharmony_ci goto error_kbdnotifier; 24058c2ecf20Sopenharmony_ci err = register_vt_notifier(&vt_notifier_block); 24068c2ecf20Sopenharmony_ci if (err) 24078c2ecf20Sopenharmony_ci goto error_vtnotifier; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci speakup_task = kthread_create(speakup_thread, NULL, "speakup"); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci if (IS_ERR(speakup_task)) { 24128c2ecf20Sopenharmony_ci err = PTR_ERR(speakup_task); 24138c2ecf20Sopenharmony_ci goto error_task; 24148c2ecf20Sopenharmony_ci } 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci set_user_nice(speakup_task, 10); 24178c2ecf20Sopenharmony_ci wake_up_process(speakup_task); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci pr_info("speakup %s: initialized\n", SPEAKUP_VERSION); 24208c2ecf20Sopenharmony_ci pr_info("synth name on entry is: %s\n", synth_name); 24218c2ecf20Sopenharmony_ci goto out; 24228c2ecf20Sopenharmony_ci 24238c2ecf20Sopenharmony_cierror_task: 24248c2ecf20Sopenharmony_ci unregister_vt_notifier(&vt_notifier_block); 24258c2ecf20Sopenharmony_ci 24268c2ecf20Sopenharmony_cierror_vtnotifier: 24278c2ecf20Sopenharmony_ci unregister_keyboard_notifier(&keyboard_notifier_block); 24288c2ecf20Sopenharmony_ci del_timer(&cursor_timer); 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_cierror_kbdnotifier: 24318c2ecf20Sopenharmony_ci speakup_unregister_devsynth(); 24328c2ecf20Sopenharmony_ci mutex_lock(&spk_mutex); 24338c2ecf20Sopenharmony_ci synth_release(); 24348c2ecf20Sopenharmony_ci mutex_unlock(&spk_mutex); 24358c2ecf20Sopenharmony_ci speakup_kobj_exit(); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_cierror_kobjects: 24388c2ecf20Sopenharmony_ci for (i = 0; i < MAX_NR_CONSOLES; i++) 24398c2ecf20Sopenharmony_ci kfree(speakup_console[i]); 24408c2ecf20Sopenharmony_ci 24418c2ecf20Sopenharmony_ci speakup_remove_virtual_keyboard(); 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_cierror_virtkeyboard: 24448c2ecf20Sopenharmony_ci for (i = 0; i < MAXVARS; i++) 24458c2ecf20Sopenharmony_ci speakup_unregister_var(i); 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) { 24488c2ecf20Sopenharmony_ci if (spk_characters[i] != spk_default_chars[i]) 24498c2ecf20Sopenharmony_ci kfree(spk_characters[i]); 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci spk_free_user_msgs(); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ciout: 24558c2ecf20Sopenharmony_ci return err; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_cimodule_init(speakup_init); 24598c2ecf20Sopenharmony_cimodule_exit(speakup_exit); 2460