cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

main.c (60175B)


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