Linux Audio

Check our new training course

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