1c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* speakup.c
216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * review functions for the speakup screen review package.
316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * originally written by: Kirk Reiser and Andy Berdan.
416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * extensively modified by David Borowski.
616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs ** Copyright (C) 1998  Kirk Reiser.
816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  Copyright (C) 2003  David Borowski.
916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
1016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  This program is free software; you can redistribute it and/or modify
1116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  it under the terms of the GNU General Public License as published by
1216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  the Free Software Foundation; either version 2 of the License, or
1316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  (at your option) any later version.
1416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
1516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  This program is distributed in the hope that it will be useful,
1616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  GNU General Public License for more details.
1916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *
2016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  You should have received a copy of the GNU General Public License
2116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  along with this program; if not, write to the Free Software
2216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs*/
24c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
25c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kernel.h>
26c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/vt.h>
27c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/tty.h>
2816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/mm.h>		/* __get_free_page() and friends */
29c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/vt_kern.h>
30c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/ctype.h>
31c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/selection.h>
32c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/unistd.h>
33c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/jiffies.h>
34c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kthread.h>
35c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/keyboard.h>	/* for KT_SHIFT */
3616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/kbd_kern.h>	/* for vc_kbd_* and friends */
37c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/input.h>
38c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/kmod.h>
39c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
40c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* speakup_*_selection */
41c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/module.h>
42c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/sched.h>
43c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/slab.h>
44c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/types.h>
45c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/consolemap.h>
46c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
47c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/spinlock.h>
48c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include <linux/notifier.h>
49c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
5016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs#include <linux/uaccess.h>	/* copy_from|to|user() and others */
51c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
52c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "spk_priv.h"
53c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "speakup.h"
54c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
55c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MAX_DELAY msecs_to_jiffies(500)
56c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MINECHOCHAR SPACE
57c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
58c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
59c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
60c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_DESCRIPTION("Speakup console speech");
61c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_LICENSE("GPL");
62c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_VERSION(SPEAKUP_VERSION);
63c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
64c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbschar *synth_name;
65c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_param_named(synth, synth_name, charp, S_IRUGO);
66ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultmodule_param_named(quiet, spk_quiet_boot, bool, S_IRUGO);
67c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
68c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
69c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsMODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
70c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
71ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultspecial_func spk_special_handler;
72c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
73ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultshort spk_pitch_shift, synth_flags;
74c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char buf[256];
75ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
76ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_no_intr, spk_spell_delay;
77ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_key_echo, spk_say_word_ctl;
78ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_say_ctrl, spk_bell_pos;
79ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultshort spk_punc_mask;
80ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_punc_level, spk_reading_punc;
81e7027b9b2567cd3050d266bc56a2296840dd7f68Domagoj Trsanchar spk_str_caps_start[MAXVARLEN + 1] = "\0";
82e7027b9b2567cd3050d266bc56a2296840dd7f68Domagoj Trsanchar spk_str_caps_stop[MAXVARLEN + 1] = "\0";
83ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultconst struct st_bits_data spk_punc_info[] = {
8416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"none", "", 0},
8516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"some", "/$%&@", SOME},
8616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"most", "$%&#()=+*/@^<>|\\", MOST},
8716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
8816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"delimiters", "", B_WDLM},
8916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"repeats", "()", CH_RPT},
9016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"extended numeric", "", B_EXNUM},
9116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{"symbols", "", B_SYM},
92ab06e0f20ed4c4eb472a1e16f942d6e0150c00bcShalin Mehta	{NULL, NULL}
93c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
9416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs
95c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char mark_cut_flag;
96c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define MAX_KEY 160
970012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic u_char *spk_shift_table;
980012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatu_char *spk_our_keys[MAX_KEY];
99ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultu_char spk_key_buf[600];
100ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultconst u_char spk_key_defaults[] = {
101c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#include "speakupmap.h"
102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Speakup Cursor Track Variables */
105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int cursor_track = 1, prev_cursor_track = 1;
106c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
107c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* cursor track modes, must be ordered same as cursor_msgs */
108c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
109c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Off = 0,
110c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_On,
111c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Highlight,
112c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Window,
113c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	CT_Max
114c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
115c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs#define read_all_mode CT_Max
116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct tty_struct *tty;
118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spkup_write(const char *in_buf, int count);
120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
121c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *phonetic[] = {
122c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
12316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	"india", "juliett", "keelo", "leema", "mike", "november", "oscar",
12416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "papa",
125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"x ray", "yankee", "zulu"
127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
128c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* array of 256 char pointers (one for each character description)
130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * initialized to default_chars and user selectable via
131c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * /proc/speakup/characters */
132ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultchar *spk_characters[256];
133c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
134ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultchar *spk_default_chars[256] = {
13516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
136c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
137c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
13816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
13916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control",
14016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
14116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "tick",
14216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
14316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "dot",
144c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"slash",
145c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"eight", "nine",
147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
15116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
15216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "caret",
153c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	"line",
154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
15816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*127*/ "del", "control", "control", "control", "control", "control",
15916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
16016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*138*/ "control", "control", "control", "control", "control",
16116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
16216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control",
16316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*150*/ "control", "control", "control", "control", "control",
16416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "control", "control", "control", "control", "control",
165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*160*/ "nbsp", "inverted bang",
16616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
16716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*172*/ "not", "soft hyphen", "registered", "macron",
16916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*176*/ "degrees", "plus or minus", "super two", "super three",
17016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
171c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
17216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*188*/ "one quarter", "one half", "three quarters",
17316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "inverted question",
17416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
17516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "A RING",
17616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
17716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "E OOMLAUT",
17816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
17916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "N TILDE",
180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
18116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
18216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "U CIRCUMFLEX",
183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/*230*/ "ae", "c cidella", "e grave", "e acute",
18616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
18716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "i circumflex",
18816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
18916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "o circumflex",
19016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
19116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    "u acute",
192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* array of 256 u_short (one for each character)
196c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * initialized to default_chartab and user selectable via
197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * /sys/module/speakup/parameters/chartab */
198c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsu_short spk_chartab[256];
199c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
200c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_short default_chartab[256] = {
20116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 0-7 */
20216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 8-15 */
20316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/*16-23 */
20416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,	/* 24-31 */
20516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/*  !"#$%&' */
20616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,	/* ()*+, -./ */
20716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM,	/* 01234567 */
20816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,	/* 89:;<=>? */
20916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* @ABCDEFG */
21016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* HIJKLMNO */
21116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* PQRSTUVW */
21216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,	/* XYZ[\]^_ */
21316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* `abcdefg */
21416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* hijklmno */
21516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* pqrstuvw */
21616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0,	/* xyz{|}~ */
21716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
21816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 135 */
21916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
22016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM,	/* 143 */
22116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
22216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 151 */
22316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
22416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 159 */
22516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
22616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM,	/* 167 */
22716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 168-175 */
22816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 176-183 */
22916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,	/* 184-191 */
23016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 192-199 */
23116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,	/* 200-207 */
23216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM,	/* 208-215 */
23316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA,	/* 216-223 */
23416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 224-231 */
23516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,	/* 232-239 */
23616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM,	/* 240-247 */
23716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA	/* 248-255 */
238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct task_struct *speakup_task;
241ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultstruct bleep spk_unprocessed_sound;
242c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int spk_keydown;
243c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char spk_lastkey, spk_close_press, keymap_flags;
244c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char last_keycode, this_speakup_key;
245c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long last_spk_jiffy;
246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstruct st_spk_t *speakup_console[MAX_NR_CONSOLES];
248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
249c6e3fd22cd538365bfeb82997d5b89562e077d42William HubbsDEFINE_MUTEX(spk_mutex);
250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
251c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int keyboard_notifier_call(struct notifier_block *,
252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				  unsigned long code, void *param);
253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
254d9f5420268ca9b2bbe62f14757fac3e10eaf1ebfSamuel Thibaultstatic struct notifier_block keyboard_notifier_block = {
255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	.notifier_call = keyboard_notifier_call,
256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int vt_notifier_call(struct notifier_block *,
259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			    unsigned long code, void *param);
260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
261d9f5420268ca9b2bbe62f14757fac3e10eaf1ebfSamuel Thibaultstatic struct notifier_block vt_notifier_block = {
262c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	.notifier_call = vt_notifier_call,
263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic unsigned char get_attributes(u16 *pos)
266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
26716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	return (u_char) (scr_readw(pos) >> 8);
268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
269c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_date(struct vc_data *vc)
271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
272c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = spk_cx = vc->vc_x;
273c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = spk_cy = vc->vc_y;
274c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos = spk_cp = vc->vc_pos;
275c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) spk_pos);
277c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
279c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void bleep(u_short val)
280c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
281c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static const short vals[] = {
282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
283c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	};
284c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	short freq;
285ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	int time = spk_bleep_time;
2868e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
28716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	freq = vals[val % 12];
288c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val > 11)
28916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		freq *= (1 << (val / 12));
290ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_unprocessed_sound.freq = freq;
291ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
292ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_unprocessed_sound.active = 1;
293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* We can only have 1 active sound at a time. */
294c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
295c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
296c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_shut_up(struct vc_data *vc)
297c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
298c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_killed)
299c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up |= 0x01;
301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
302c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
303c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth != NULL)
304ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
305c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
307c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speech_kill(struct vc_data *vc)
308c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
309c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char val = synth->is_alive(synth);
3108e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val == 0)
312c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
313c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* re-enables synth, if disabled */
315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (val == 2 || spk_killed) {
316c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* dead */
317c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= ~0x40;
318ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
319c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
320ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
321c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up |= 0x40;
322c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
323c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
324c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
325c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_off(struct vc_data *vc)
326c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
327c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_shut_up & 0x80) {
328c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0x7f;
329ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
330c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
331c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up |= 0x80;
332ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
333c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
334c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
335c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
336c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
337c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_parked(struct vc_data *vc)
338c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
339c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_parked & 0x80) {
340c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked = 0;
341ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
342c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
343c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked |= 0x80;
344ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_PARKED));
345c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
346c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
347c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
348c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_cut(struct vc_data *vc)
349c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
350c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static const char err_buf[] = "set selection failed";
351c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret;
352c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
353c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!mark_cut_flag) {
354c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		mark_cut_flag = 1;
355ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_xs = (u_short) spk_x;
356ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_ys = (u_short) spk_y;
357c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_sel_cons = vc;
358ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_MARK));
359c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
360c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
361ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_xe = (u_short) spk_x;
362ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_ye = (u_short) spk_y;
363c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mark_cut_flag = 0;
364ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s\n", spk_msg_get(MSG_CUT));
365c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
366c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_clear_selection();
367c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ret = speakup_set_selection(tty);
368c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
369c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (ret) {
370c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case 0:
37116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		break;		/* no error */
37216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -EFAULT:
373c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sEFAULT\n", err_buf);
374c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
37516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -EINVAL:
376c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sEINVAL\n", err_buf);
377c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
37816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case -ENOMEM:
379c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_warn("%sENOMEM\n", err_buf);
380c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
381c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
382c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
383c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
384c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_paste(struct vc_data *vc)
385c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
386c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (mark_cut_flag) {
387c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		mark_cut_flag = 0;
388ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
389c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
390ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_PASTE));
391c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_paste_selection(tty);
392c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
393c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
394c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
395c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_attributes(struct vc_data *vc)
396c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
397c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int fg = spk_attr & 0x0f;
398c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int bg = spk_attr >> 4;
3998e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
400c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (fg > 8) {
401ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
402c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		fg -= 8;
403c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
404ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
405c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (bg > 7) {
406ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
407c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bg -= 8;
408c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else
409ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf(" %s ", spk_msg_get(MSG_ON));
410ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
411c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
412c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
413c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
414c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_top = 1,
415c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_bottom,
416c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_left,
417c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_right,
418c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	edge_quiet
419c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
420c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
421c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void announce_edge(struct vc_data *vc, int msg_id)
422c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
423ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_bleeps & 1)
424c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bleep(spk_y);
425ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if ((spk_bleeps & 2) && (msg_id < edge_quiet))
426ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
427c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
428c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
429c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speak_char(u_char ch)
430c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
431ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	char *cp = spk_characters[ch];
432ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	struct var_t *direct = spk_get_var(DIRECT);
4338e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
434c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (direct && direct->u.n.value) {
435c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP)) {
436ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			spk_pitch_shift++;
437ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf("%s", spk_str_caps_start);
438c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
439c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%c", ch);
440c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP))
441ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf("%s", spk_str_caps_stop);
442c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
443c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
444c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cp == NULL) {
445c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		pr_info("speak_char: cp == NULL!\n");
446c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
447c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
448c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_buffer_add(SPACE);
449c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (IS_CHAR(ch, B_CAP)) {
450ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_pitch_shift++;
451ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s", spk_str_caps_start);
452c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp);
453ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s", spk_str_caps_stop);
454c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
455c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*cp == '^') {
456ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf("%s", spk_msg_get(MSG_CTRL));
457c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cp++;
458c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
459c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp);
460c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
461c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_buffer_add(SPACE);
462c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
463c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
46469d8ba56594a23af4901e109a5b9178105b863b3Lisa Nguyenstatic u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
465c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
466c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 ch = ' ';
4678e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
468c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc && pos) {
469c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 w = scr_readw(pos);
470c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 c = w & 0xff;
471c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
472c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (w & vc->vc_hi_font_mask)
473c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			c |= 0x100;
474c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
475c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = inverse_translate(vc, c, 0);
476c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		*attribs = (w & 0xff00) >> 8;
477c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
478c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ch;
479c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
480c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
481c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_char(struct vc_data *vc)
482c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
483c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch;
4848e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
485c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
486c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
487c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_attr != spk_old_attr) {
488ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if (spk_attrib_bleep & 1)
489c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(spk_y);
490ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if (spk_attrib_bleep & 2)
491c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_attributes(vc);
492c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
493c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch & 0xff);
494c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
495c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
496c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_phonetic_char(struct vc_data *vc)
497c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
498c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch;
4998e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
500c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
501c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = get_char(vc, (u_short *) spk_pos, &spk_attr);
502c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (isascii(ch) && isalpha(ch)) {
503c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch &= 0x1f;
504c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s\n", phonetic[--ch]);
505c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
506c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_NUM))
507ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf("%s ", spk_msg_get(MSG_NUMBER));
508c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speak_char(ch);
509c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
510c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
511c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
512c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_char(struct vc_data *vc)
513c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
514c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
515c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0) {
516c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_left);
517c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
518c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
519c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x--;
520c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= 2;
521c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
522c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
523c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
524c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_char(struct vc_data *vc)
525c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
526c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
527c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == vc->vc_cols - 1) {
528c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_right);
529c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
530c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
531c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x++;
532c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += 2;
533c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
534c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
535c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
536c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* get_word - will first check to see if the character under the
537ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault * reading cursor is a space and if spk_say_word_ctl is true it will
538ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault * return the word space.  If spk_say_word_ctl is not set it will check to
53916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * see if there is a word starting on the next position to the right
54016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * and return that word if it exists.  If it does not exist it will
54116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * move left to the beginning of any previous word on the line or the
54216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs * beginning off the line whichever comes first.. */
543c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
544c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long get_word(struct vc_data *vc)
545c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
546c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
547c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
548c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short attr_ch;
549c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
5508e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
551c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
55216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
553c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
554c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* decided to take out the sayword if on a space (mis-information */
555ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_say_word_ctl && ch == SPACE) {
556c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		*buf = '\0';
557ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_SPACE));
558c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
559c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else if ((tmpx < vc->vc_cols - 2)
560c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		   && (ch == SPACE || ch == 0 || IS_WDLM(ch))
56116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		   && ((char)get_char(vc, (u_short *) &tmp_pos + 1, &temp) >
56216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		       SPACE)) {
563c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp_pos += 2;
564c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmpx++;
565c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else
566c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		while (tmpx > 0) {
56716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			ch = (char)get_char(vc, (u_short *) tmp_pos - 1, &temp);
568c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((ch == SPACE || ch == 0 || IS_WDLM(ch))
56916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    && ((char)get_char(vc, (u_short *) tmp_pos, &temp) >
57016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				SPACE))
571c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
572c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			tmp_pos -= 2;
573c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			tmpx--;
574c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
575c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	attr_ch = get_char(vc, (u_short *) tmp_pos, &spk_attr);
576c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt++] = attr_ch & 0xff;
577c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (tmpx < vc->vc_cols - 1) {
578c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp_pos += 2;
579c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmpx++;
58016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) tmp_pos, &temp);
58116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if ((ch == SPACE) || ch == 0
58216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    || (IS_WDLM(buf[cnt - 1]) && (ch > SPACE)))
583c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
584c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		buf[cnt++] = ch;
585c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
586c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt] = '\0';
587c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return cnt;
588c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
589c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
590c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_word(struct vc_data *vc)
591c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
592c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long cnt = get_word(vc);
593ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	u_short saved_punc_mask = spk_punc_mask;
5948e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
595c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cnt == 0)
596c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
597ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_punc_mask = PUNC;
598c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[cnt++] = SPACE;
599c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, cnt);
600ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_punc_mask = saved_punc_mask;
601c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
602c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
603c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_word(struct vc_data *vc)
604c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
605c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
606c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
607c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short edge_said = 0, last_state = 0, state = 0;
6088e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
609c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
610c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
611c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0) {
612c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_y == 0) {
613c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			announce_edge(vc, edge_top);
614c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return;
615c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
616c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y--;
617c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = vc->vc_cols;
618c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		edge_said = edge_quiet;
619c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
620c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (1) {
621c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_x == 0) {
622c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (spk_y == 0) {
623c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_top;
624c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
625c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
626c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (edge_said != edge_quiet)
627c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_left;
628c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (state > 0)
629c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
630c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_y--;
631c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x = vc->vc_cols - 1;
632c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
633c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x--;
63416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		spk_pos -= 2;
63516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
636c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == SPACE || ch == 0)
637c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
638c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (IS_WDLM(ch))
639c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 1;
640c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
641c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 2;
642c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (state < last_state) {
643c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_pos += 2;
644c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x++;
645c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
646c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
647c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_state = state;
648c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
649c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == 0 && edge_said == edge_quiet)
650c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		edge_said = edge_left;
651c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (edge_said > 0 && edge_said < edge_quiet)
652c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_said);
653c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word(vc);
654c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
655c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
656c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_word(struct vc_data *vc)
657c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
658c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char temp;
659c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char ch;
660c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short edge_said = 0, last_state = 2, state = 0;
661c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
6628e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan	spk_parked |= 0x01;
663c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
664c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_bottom);
665c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
666c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
667c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (1) {
66816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (char)get_char(vc, (u_short *) spk_pos, &temp);
669c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == SPACE || ch == 0)
670c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
671c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (IS_WDLM(ch))
672c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 1;
673c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
674c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 2;
675c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (state > last_state)
676c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
677c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (spk_x >= vc->vc_cols - 1) {
678c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (spk_y == vc->vc_rows - 1) {
679c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				edge_said = edge_bottom;
680c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				break;
681c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
682c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			state = 0;
683c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_y++;
684c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x = 0;
685c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			edge_said = edge_right;
686c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
687c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_x++;
688c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos += 2;
689c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_state = state;
690c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
691c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (edge_said > 0)
692c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_said);
693c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word(vc);
694c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
695c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
696c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spell_word(struct vc_data *vc)
697c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
698c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static char *delay_str[] = { "", ",", ".", ". .", ". . ." };
699ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	char *cp = buf, *str_cap = spk_str_caps_stop;
700ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	char *cp1, *last_cap = spk_str_caps_stop;
701c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
7028e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
703c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!get_word(vc))
704c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
705c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((ch = (u_char) *cp)) {
706c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cp != buf)
707ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf(" %s ", delay_str[spk_spell_delay]);
708c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (IS_CHAR(ch, B_CAP)) {
709ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			str_cap = spk_str_caps_start;
710ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			if (*spk_str_caps_stop)
711ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				spk_pitch_shift++;
71216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			else	/* synth has no pitch */
713ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				last_cap = spk_str_caps_stop;
714c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else
715ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			str_cap = spk_str_caps_stop;
716c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (str_cap != last_cap) {
717c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%s", str_cap);
718c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_cap = str_cap;
719c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
720c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (this_speakup_key == SPELL_PHONETIC
721c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		    && (isascii(ch) && isalpha(ch))) {
722c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ch &= 31;
723c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cp1 = phonetic[--ch];
724c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
725ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			cp1 = spk_characters[ch];
726c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (*cp1 == '^') {
727ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				synth_printf("%s", spk_msg_get(MSG_CTRL));
728c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cp1++;
729c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
730c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
731c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s", cp1);
732c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cp++;
733c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
734ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (str_cap != spk_str_caps_stop)
735ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s", spk_str_caps_stop);
736c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
737c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
738c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int get_line(struct vc_data *vc)
739c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
740c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long tmp = spk_pos - (spk_x * 2);
741c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0;
742c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp2;
743c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
744c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
745c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) spk_pos);
746c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < vc->vc_cols; i++) {
747c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		buf[i] = (u_char) get_char(vc, (u_short *) tmp, &tmp2);
748c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		tmp += 2;
749c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
750c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
751c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
752c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
753c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ++i;
754c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
755c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
756c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_line(struct vc_data *vc)
757c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
758c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = get_line(vc);
759c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp;
760ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	u_short saved_punc_mask = spk_punc_mask;
7618e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
762c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i == 0) {
763ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
764c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
765c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
766c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[i++] = '\n';
767c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (this_speakup_key == SAY_LINE_INDENT) {
76816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		cp = buf;
76916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		while (*cp == SPACE)
77016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			cp++;
771c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%d, ", (cp - buf) + 1);
772c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
773ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_punc_mask = spk_punc_masks[spk_reading_punc];
774c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, i);
775ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_punc_mask = saved_punc_mask;
776c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
777c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
778c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_prev_line(struct vc_data *vc)
779c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
780c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
781c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_y == 0) {
782c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_top);
783c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
784c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
785c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y--;
786c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= vc->vc_size_row;
787c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
788c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
789c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
790c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_next_line(struct vc_data *vc)
791c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
792c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
793c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_y == vc->vc_rows - 1) {
794c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		announce_edge(vc, edge_bottom);
795c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
796c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
797c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y++;
798c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += vc->vc_size_row;
799c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
800c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
801c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
802c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int say_from_to(struct vc_data *vc, u_long from, u_long to,
803c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		       int read_punc)
804c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
805c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0;
806c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
807ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	u_short saved_punc_mask = spk_punc_mask;
8088e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
809c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
810c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) from);
811c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (from < to) {
81216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		buf[i++] = (char)get_char(vc, (u_short *) from, &tmp);
813c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		from += 2;
814c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i >= vc->vc_size_row)
815c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
816c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
817c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
818c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
819c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
820c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[++i] = SPACE;
821c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	buf[++i] = '\0';
822c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i < 1)
823c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return i;
824c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (read_punc)
825ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
826c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(buf, i);
827c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (read_punc)
828ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_punc_mask = saved_punc_mask;
829c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return i - 1;
830c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
831c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
832c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
833c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			     int read_punc)
834c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
835c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
836c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long end = start + (to * 2);
8378e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
838c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start += from * 2;
839c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (say_from_to(vc, start, end, read_punc) <= 0)
840c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track != read_all_mode)
841ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf("%s\n", spk_msg_get(MSG_BLANK));
842c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
843c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
844c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Sentence Reading Commands */
845c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
846c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int currsentence;
847c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int numsentences[2];
848c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *sentbufend[2];
849c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char *sentmarks[2][10];
850c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int currbuf;
851c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int bn;
852c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic char sentbuf[2][256];
853c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
85416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int say_sentence_num(int num, int prev)
855c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
856c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	bn = currbuf;
857c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	currsentence = num + 1;
858c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (prev && --bn == -1)
859c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bn = 1;
860c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
861c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (num > numsentences[bn])
862c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
863c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
864c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
865c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
866c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
867c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
868c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int get_sentence_buf(struct vc_data *vc, int read_punc)
869c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
870c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start, end;
871c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bn;
872c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
873c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
874c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	currbuf++;
875c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (currbuf == 2)
876c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		currbuf = 0;
877c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	bn = currbuf;
878c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
87916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
880c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
881c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	numsentences[bn] = 0;
882c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentmarks[bn][0] = &sentbuf[bn][0];
883c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	i = 0;
884c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_old_attr = spk_attr;
885c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_attr = get_attributes((u_short *) start);
886c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
887c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (start < end) {
88816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		sentbuf[bn][i] = (char)get_char(vc, (u_short *) start, &tmp);
889c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i > 0) {
89016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (sentbuf[bn][i] == SPACE && sentbuf[bn][i - 1] == '.'
891c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			    && numsentences[bn] < 9) {
892c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				/* Sentence Marker */
893c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				numsentences[bn]++;
894c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				sentmarks[bn][numsentences[bn]] =
89516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				    &sentbuf[bn][i];
896c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
897c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
898c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		i++;
899c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += 2;
900c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (i >= vc->vc_size_row)
901c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
902c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
903c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
904c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (--i; i >= 0; i--)
905c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (sentbuf[bn][i] != SPACE)
906c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
907c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
908c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (i < 1)
909c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
910c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
911c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbuf[bn][++i] = SPACE;
912c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbuf[bn][++i] = '\0';
913c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
914c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	sentbufend[bn] = &sentbuf[bn][i];
915c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return numsentences[bn];
916c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
917c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
918c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
919c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
920c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start = vc->vc_origin, end;
9218e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
922c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (from > 0)
923c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += from * vc->vc_size_row;
924c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (to > vc->vc_rows)
925c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = vc->vc_rows;
926c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	end = vc->vc_origin + (to * vc->vc_size_row);
927c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (from = start; from < end; from = to) {
928c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = from + vc->vc_size_row;
929c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_from_to(vc, from, to, 1);
930c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
931c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
932c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
933c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_screen(struct vc_data *vc)
934c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
935c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, 0, vc->vc_rows);
936c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
937c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
938c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_win_say(struct vc_data *vc)
939c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
940c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_long start, end, from, to;
9418e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
942c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start < 2) {
943ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
944c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
945c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
946c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start = vc->vc_origin + (win_top * vc->vc_size_row);
947c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	end = vc->vc_origin + (win_bottom * vc->vc_size_row);
948c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (start <= end) {
949c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		from = start + (win_left * 2);
950c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		to = start + (win_right * 2);
951c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_from_to(vc, from, to, 1);
952c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += vc->vc_size_row;
953c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
954c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
955c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
956c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void top_edge(struct vc_data *vc)
957c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
958c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
959c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos = vc->vc_origin + 2 * spk_x;
960c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = 0;
961c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
962c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
963c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
964c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void bottom_edge(struct vc_data *vc)
965c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
966c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
967c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
968c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_y = vc->vc_rows - 1;
969c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line(vc);
970c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
971c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
972c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void left_edge(struct vc_data *vc)
973c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
974c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
975c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= spk_x * 2;
976c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = 0;
977c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
978c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
979c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
980c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void right_edge(struct vc_data *vc)
981c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
982c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
983c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos += (vc->vc_cols - spk_x - 1) * 2;
984c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = vc->vc_cols - 1;
985c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char(vc);
986c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
987c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
988c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_first_char(struct vc_data *vc)
989c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
990c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, len = get_line(vc);
991c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
9928e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
993c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
994c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (len == 0) {
995ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
996c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
997c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
998c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < len; i++)
999c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (buf[i] != SPACE)
1000c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
1001c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = buf[i];
1002c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= (spk_x - i) * 2;
1003c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = i;
1004c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%d, ", ++i);
1005c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
1006c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1007c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1008c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_last_char(struct vc_data *vc)
1009c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1010c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int len = get_line(vc);
1011c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch;
10128e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1013c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
1014c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (len == 0) {
1015ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1016c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1017c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1018c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch = buf[--len];
1019c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_pos -= (spk_x - len) * 2;
1020c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_x = len;
1021c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%d, ", ++len);
1022c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
1023c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1024c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1025c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_position(struct vc_data *vc)
1026c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1027ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
102816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		     vc->vc_num + 1);
1029c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("\n");
1030c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1031c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1032c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Added by brianb */
1033c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_char_num(struct vc_data *vc)
1034c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1035c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char tmp;
1036c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_short ch = get_char(vc, (u_short *) spk_pos, &tmp);
10378e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1038c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	ch &= 0xff;
1039ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1040c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1041c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1042c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* these are stub functions to keep keyboard.c happy. */
1043c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1044c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_from_top(struct vc_data *vc)
1045c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1046c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, 0, spk_y);
1047c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1048c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1049c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_to_bottom(struct vc_data *vc)
1050c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1051c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_screen_from_to(vc, spk_y, vc->vc_rows);
1052c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1053c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1054c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_from_left(struct vc_data *vc)
1055c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1056c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line_from_to(vc, 0, spk_x, 1);
1057c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1058c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1059c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void say_to_right(struct vc_data *vc)
1060c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1061c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1062c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1063c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1064c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* end of stub functions. */
1065c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1066c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void spkup_write(const char *in_buf, int count)
1067c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
106816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int rep_count;
1069c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	static u_char ch = '\0', old_ch = '\0';
107016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static u_short char_type, last_type;
1071c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int in_count = count;
10728e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1073c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = 0;
1074c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while (count--) {
1075c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track == read_all_mode) {
1076c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			/* Insert Sentence Index */
1077c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((in_buf == sentmarks[bn][currsentence]) &&
107816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    (currsentence <= numsentences[bn]))
1079c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_insert_next_index(currsentence++);
1080c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
108116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		ch = (u_char) *in_buf++;
1082c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		char_type = spk_chartab[ch];
108316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if (ch == old_ch && !(char_type & B_NUM)) {
1084c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (++rep_count > 2)
1085c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				continue;
1086c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
108716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if ((last_type & CH_RPT) && rep_count > 2) {
1088c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf(" ");
1089ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				synth_printf(spk_msg_get(MSG_REPEAT_DESC),
109016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs					     ++rep_count);
1091c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf(" ");
1092c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1093c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1094c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1095c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch == spk_lastkey) {
1096c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1097ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1098c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				speak_char(ch);
1099c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (char_type & B_ALPHA) {
1100c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if ((synth_flags & SF_DEC) && (last_type & PUNC))
1101c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_buffer_add(SPACE);
1102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%c", ch);
1103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (char_type & B_NUM) {
1104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			rep_count = 0;
1105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf("%c", ch);
1106ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		} else if (char_type & spk_punc_mask) {
1107c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speak_char(ch);
110816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			char_type &= ~PUNC;	/* for dec nospell processing */
110916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		} else if (char_type & SYNTH_OK) {
111016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			/* these are usually puncts like . and , which synth
111116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * needs for expression.
111216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * suppress multiple to get rid of long pauses and
111316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * clear repeat count
111416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * so if someone has
111516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 * repeats on you don't get nothing repeated count */
1116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (ch != old_ch)
1117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_printf("%c", ch);
1118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				rep_count = 0;
1120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1121c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* send space and record position, if next is num overwrite space */
1122c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (old_ch != ch)
1123c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_buffer_add(SPACE);
1124c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				rep_count = 0;
1126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		old_ch = ch;
1128c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		last_type = char_type;
1129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = 0;
1131c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (in_count > 2 && rep_count > 2) {
113216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		if (last_type & CH_RPT) {
1133c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" ");
1134ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf(spk_msg_get(MSG_REPEAT_DESC2), ++rep_count);
1135c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_printf(" ");
1136c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1137c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		rep_count = 0;
1138c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1139c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1140c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1141c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1142c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1143c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void read_all_doc(struct vc_data *vc);
1144c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void cursor_done(u_long data);
1145c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic DEFINE_TIMER(cursor_timer, cursor_done, 0, 0);
1146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
11508e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1151c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_killed)
1152c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
11533efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		switch (value) {
1156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_SHIFT):
1157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			del_timer(&cursor_timer);
1158c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_shut_up &= 0xfe;
1159ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			spk_do_flush();
1160c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			read_all_doc(vc);
1161c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
1162c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_CTRL):
1163c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			del_timer(&cursor_timer);
1164c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cursor_track = prev_cursor_track;
1165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_shut_up &= 0xfe;
1166ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			spk_do_flush();
1167c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
1168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1169c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1170c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0xfe;
1171ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
1172c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1173ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_say_ctrl && value < NUM_CTL_LABELS)
1174ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
11753efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1176c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1177c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1178c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1179c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
11818e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
11823efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (up_flag) {
1184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_lastkey = spk_keydown = 0;
11853efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1186c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1187c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1188c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || spk_killed) {
11893efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1190c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1191c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = value;
1194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown++;
1195c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
1196ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_key_echo == 2 && value >= MINECHOCHAR)
1197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speak_char(value);
11983efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1199c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1200c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1201ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultint spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1202c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1203c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i = 0, states, key_data_len;
1204c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	const u_char *cp = key_info;
1205c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char *cp1 = k_buffer;
1206c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char ch, version, num_keys;
12078e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1208c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	version = *cp++;
1209c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (version != KEY_MAP_VER)
1210c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1211c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	num_keys = *cp;
121216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	states = (int)cp[1];
1213c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	key_data_len = (states + 1) * (num_keys + 1);
1214ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf))
1215c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -2;
1216c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memset(k_buffer, 0, SHIFT_TBL_SIZE);
1217ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	memset(spk_our_keys, 0, sizeof(spk_our_keys));
1218ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_shift_table = k_buffer;
1219ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_our_keys[0] = spk_shift_table;
1220c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cp1 += SHIFT_TBL_SIZE;
1221c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memcpy(cp1, cp, key_data_len + 3);
122216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	/* get num_keys, states and data */
122316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	cp1 += 2;		/* now pointing at shift states */
1224c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 1; i <= states; i++) {
1225c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = *cp1++;
1226c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch >= SHIFT_TBL_SIZE)
1227c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -3;
1228ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_shift_table[ch] = i;
1229c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1230c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	keymap_flags = *cp1++;
1231c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((ch = *cp1)) {
1232c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ch >= MAX_KEY)
1233c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -4;
1234ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_our_keys[ch] = cp1;
1235c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cp1 += states + 1;
1236c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1237c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1240c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic struct var_t spk_vars[] = {
1241c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* bell must be first to set high limit */
124216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
124316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
124416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
124516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
124616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
124716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
124816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
124916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
125016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SAY_CONTROL, TOGGLE_0},
125116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{SAY_WORD_CTL, TOGGLE_0},
125216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{NO_INTERRUPT, TOGGLE_0},
125316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	{KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	V_LAST_VAR
1255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
1256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void toggle_cursoring(struct vc_data *vc)
1258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode)
1260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cursor_track = prev_cursor_track;
1261c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (++cursor_track >= CT_Max)
1262c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cursor_track = 0;
1263ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1266ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultvoid spk_reset_default_chars(void)
1267c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
1269c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1270c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* First, free any non-default */
1271c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 256; i++) {
1272ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if ((spk_characters[i] != NULL)
1273ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		    && (spk_characters[i] != spk_default_chars[i]))
1274ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			kfree(spk_characters[i]);
1275c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1277ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1279c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1280ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibaultvoid spk_reset_default_chartab(void)
1281c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1283c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1284c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
128516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic const struct st_bits_data *pb_edit;
1286c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1287c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1288c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1289c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	short mask = pb_edit->mask, ch_type = spk_chartab[ch];
12908e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
129116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1292c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch == SPACE) {
1294ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1295ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_special_handler = NULL;
1296c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1297c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
129816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (mask < PUNC && !(ch_type & PUNC))
1299c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1300c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_chartab[ch] ^= mask;
1301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speak_char(ch);
1302c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf(" %s\n",
1303ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		     (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1304ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		     spk_msg_get(MSG_OFF));
1305c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
1306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1307c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1308c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* Allocation concurrency is protected by the console semaphore */
13090012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic int speakup_allocate(struct vc_data *vc)
1310c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num;
1312c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1313c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	vc_num = vc->vc_num;
1314c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc_num] == NULL) {
1315c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
131616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs						  GFP_ATOMIC);
1317c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num] == NULL)
1318628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			return -ENOMEM;
1319c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1320c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else if (!spk_parked)
1321c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1322628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
1323628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	return 0;
1324c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1325c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
13260012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic void speakup_deallocate(struct vc_data *vc)
1327c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1328c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num;
1329c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1330c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	vc_num = vc->vc_num;
133139dd3e5d7b09b5a5010ed1aef512f2d58b65cb99Ilia Mirkin	kfree(speakup_console[vc_num]);
133239dd3e5d7b09b5a5010ed1aef512f2d58b65cb99Ilia Mirkin	speakup_console[vc_num] = NULL;
1333c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1334c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1335c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char is_cursor;
1336c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1337c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int cursor_con;
1338c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1339c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void reset_highlight_buffers(struct vc_data *);
1340c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1341c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int read_all_key;
1342c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1343c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void start_read_all_timer(struct vc_data *vc, int command);
1344c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1345c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsenum {
1346c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NOTHING,
1347c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NEXT_SENT,
1348c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_PREV_LINE,
1349c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_NEXT_LINE,
1350c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_PREV_SENT,
1351c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_DOWN_ARROW,
1352c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_TIMER,
1353c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_FIND_NEXT_SENT,
1354c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	RA_FIND_PREV_SENT,
1355c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
1356c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
135716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void kbd_fakekey2(struct vc_data *vc, int command)
1358c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1359c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
1360c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_fake_down_arrow();
1361c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	start_read_all_timer(vc, command);
1362c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1363c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
136416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void read_all_doc(struct vc_data *vc)
1365c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1366c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((vc->vc_num != fg_console) || synth == NULL || spk_shut_up)
1367c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1368c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!synth_supports_indexing())
1369c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1370c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track != read_all_mode)
1371c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		prev_cursor_track = cursor_track;
1372c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_track = read_all_mode;
1373ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_reset_index_count(0);
1374c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (get_sentence_buf(vc, 0) == -1)
1375c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		kbd_fakekey2(vc, RA_DOWN_ARROW);
1376c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else {
1377c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_sentence_num(0, 0);
1378c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_insert_next_index(0);
1379c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start_read_all_timer(vc, RA_TIMER);
1380c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1381c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1382c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
138316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void stop_read_all(struct vc_data *vc)
1384c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1385c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
1386c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_track = prev_cursor_track;
1387c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1388ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_do_flush();
1389c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1390c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
139116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void start_read_all_timer(struct vc_data *vc, int command)
1392c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1393c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *cursor_timeout;
1394c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1395c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_con = vc->vc_num;
1396c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	read_all_key = command;
1397ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	cursor_timeout = spk_get_var(CURSOR_TIME);
139816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	mod_timer(&cursor_timer,
139916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1400c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1401c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
140216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void handle_cursor_read_all(struct vc_data *vc, int command)
1403c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1404c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int indcount, sentcount, rv, sn;
1405c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1406c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (command) {
1407c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_NEXT_SENT:
1408c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Get Current Sentence */
1409ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_get_index_count(&indcount, &sentcount);
1410c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/*printk("%d %d  ", indcount, sentcount); */
1411ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_reset_index_count(sentcount + 1);
1412c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (indcount == 1) {
141316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (!say_sentence_num(sentcount + 1, 0)) {
1414c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1415c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return;
1416c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1417c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1418c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1419c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			sn = 0;
142016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (!say_sentence_num(sentcount + 1, 1)) {
1421c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				sn = 1;
1422ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				spk_reset_index_count(sn);
1423c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			} else
1424c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				synth_insert_next_index(0);
1425c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (!say_sentence_num(sn, 0)) {
1426c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1427c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return;
1428c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1429c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1430c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1431c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start_read_all_timer(vc, RA_TIMER);
1432c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1433c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_PREV_SENT:
1434c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1435c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_NEXT_LINE:
1436c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		read_all_doc(vc);
1437c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1438c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_PREV_LINE:
1439c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1440c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_DOWN_ARROW:
1441c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (get_sentence_buf(vc, 0) == -1) {
1442c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_DOWN_ARROW);
1443c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1444c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_sentence_num(0, 0);
1445c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1446c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1447c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1448c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1449c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_FIND_NEXT_SENT:
1450c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		rv = get_sentence_buf(vc, 0);
1451c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (rv == -1)
1452c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			read_all_doc(vc);
1453c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (rv == 0)
1454c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1455c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else {
1456c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_sentence_num(1, 0);
1457c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			synth_insert_next_index(0);
1458c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1459c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1460c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1461c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_FIND_PREV_SENT:
1462c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1463c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case RA_TIMER:
1464ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_get_index_count(&indcount, &sentcount);
1465c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (indcount < 2)
1466c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			kbd_fakekey2(vc, RA_DOWN_ARROW);
1467c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else
1468c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			start_read_all_timer(vc, RA_TIMER);
1469c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1470c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1471c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1472c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1473c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1474c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1475c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
14768e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
14773efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1478c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1479c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
1480c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (synth == NULL || up_flag || spk_shut_up) {
14813efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs			spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1482c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return NOTIFY_STOP;
1483c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1484c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		del_timer(&cursor_timer);
1485c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_shut_up &= 0xfe;
1486ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
148716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		start_read_all_timer(vc, value + 1);
14883efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1489c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return NOTIFY_STOP;
1490c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
14913efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1492c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return NOTIFY_OK;
1493c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1494c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1495c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1496c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1497c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1498c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *cursor_timeout;
1499c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
15003efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1501c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked &= 0xfe;
1502c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) {
15033efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1504c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1505c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1506c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1507ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_no_intr)
1508ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
1509c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* the key press flushes if !no_inter but we want to flush on cursor
1510c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs * moves regardless of no_inter state */
1511c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	is_cursor = value + 1;
1512c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_pos = vc->vc_pos;
1513c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_x = vc->vc_x;
1514c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	old_cursor_y = vc->vc_y;
1515c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_console[vc->vc_num]->ht.cy = vc->vc_y;
1516c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cursor_con = vc->vc_num;
1517c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Highlight)
1518c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		reset_highlight_buffers(vc);
1519ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	cursor_timeout = spk_get_var(CURSOR_TIME);
152016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	mod_timer(&cursor_timer,
152116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		  jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
15223efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1523c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1524c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
152516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void update_color_buffer(struct vc_data *vc, const char *ic, int len)
1526c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1527c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bi, hi;
1528c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1529c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
153016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	bi = ((vc->vc_attr & 0x70) >> 4);
1531c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	hi = speakup_console[vc_num]->ht.highsize[bi];
1532c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1533c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	i = 0;
1534c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1535c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1536c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.rx[bi] = vc->vc_x;
1537c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.ry[bi] = vc->vc_y;
1538c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1539c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1540c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if ((ic[i] > 32) && (ic[i] < 127)) {
1541c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1542c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			hi++;
1543c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if ((ic[i] == 32) && (hi != 0)) {
154416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
154516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    32) {
1546c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				speakup_console[vc_num]->ht.highbuf[bi][hi] =
154716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				    ic[i];
1548c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				hi++;
1549c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1550c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1551c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		i++;
1552c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1553c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_console[vc_num]->ht.highsize[bi] = hi;
1554c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1555c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
155616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void reset_highlight_buffers(struct vc_data *vc)
1557c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1558c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
1559c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
15608e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
156116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (i = 0; i < 8; i++)
1562c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.highsize[i] = 0;
1563c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1564c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
156516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int count_highlight_color(struct vc_data *vc)
1566c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1567c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, bg;
1568c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int cc;
1569c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1570c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 ch;
1571c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u16 *start = (u16 *) vc->vc_origin;
1572c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1573c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1574c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_console[vc_num]->ht.bgcount[i] = 0;
1575c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1576c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < vc->vc_rows; i++) {
157716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		u16 *end = start + vc->vc_cols * 2;
1578c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		u16 *ptr;
15798e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1580c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (ptr = start; ptr < end; ptr++) {
1581c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ch = get_attributes(ptr);
1582c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bg = (ch & 0x70) >> 4;
1583c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc_num]->ht.bgcount[bg]++;
1584c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1585c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		start += vc->vc_size_row;
1586c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1587c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1588c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	cc = 0;
1589c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1590c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1591c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			cc++;
1592c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return cc;
1593c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1594c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
159516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int get_highlight_color(struct vc_data *vc)
1596c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1597c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i, j;
1598c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned int cptr[8], tmp;
1599c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
1600c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1601c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1602c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		cptr[i] = i;
1603c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1604c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 7; i++)
1605c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (j = i + 1; j < 8; j++)
1606c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
160716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    speakup_console[vc_num]->ht.bgcount[cptr[j]]) {
1608c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				tmp = cptr[i];
1609c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cptr[i] = cptr[j];
1610c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				cptr[j] = tmp;
1611c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
1612c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1613c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 8; i++)
1614c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1615c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1616c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return cptr[i];
1617c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return -1;
1618c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1619c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
162016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int speak_highlight(struct vc_data *vc)
1621c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1622c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int hc, d;
1623c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int vc_num = vc->vc_num;
16248e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1625c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (count_highlight_color(vc) == 1)
1626c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
1627c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	hc = get_highlight_color(vc);
1628c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (hc != -1) {
162916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		d = vc->vc_y - speakup_console[vc_num]->ht.cy;
1630c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if ((d == 1) || (d == -1))
1631c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y)
1632c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				return 0;
1633c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked |= 0x01;
1634ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
1635c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
163616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    speakup_console[vc_num]->ht.highsize[hc]);
1637c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1638c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1639c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1640c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1641c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1642c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1643c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1644c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
164516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void cursor_done(u_long data)
1646c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1647c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = vc_cons[cursor_con].d;
1648c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
16498e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1650c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
16513efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1652c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_con != fg_console) {
1653c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		is_cursor = 0;
1654c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
1655c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1656c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
1657c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled) {
1658c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
165916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
1660c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = is_cursor = 0;
1661c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
1662c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1663c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1664c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == read_all_mode) {
1665c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		handle_cursor_read_all(vc, read_all_key);
1666c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
1667c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1668c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Highlight) {
1669c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speak_highlight(vc)) {
1670c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = is_cursor = 0;
1671c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
1672c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1673c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1674c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (cursor_track == CT_Window)
1675c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_win_say(vc);
1676c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else if (is_cursor == 1 || is_cursor == 4)
1677c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_line_from_to(vc, 0, vc->vc_cols, 0);
1678c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1679c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_char(vc);
1680c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = is_cursor = 0;
1681c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsout:
16823efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1683c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1684c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1685c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: vt_notifier_call() */
1686c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_bs(struct vc_data *vc)
1687c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1688c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
16898e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1690c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!speakup_console[vc->vc_num])
1691c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
16923efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1693c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1694c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1695c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_parked)
1696c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_date(vc);
1697c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_shut_up || synth == NULL) {
16983efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1699c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1700c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1701c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc->vc_num == fg_console && spk_keydown) {
1702c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_keydown = 0;
1703c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!is_cursor)
1704c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			say_char(vc);
1705c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
17063efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1707c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1708c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1709c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: vt_notifier_call() */
1710c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_con_write(struct vc_data *vc, const char *str, int len)
1711c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1712c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
17138e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1714c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL)
1715c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
17163efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1717c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1718c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1719ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_bell_pos && spk_keydown && (vc->vc_x == spk_bell_pos - 1))
1720c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		bleep(3);
1721c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((is_cursor) || (cursor_track == read_all_mode)) {
1722c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (cursor_track == CT_Highlight)
1723c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			update_color_buffer(vc, str, len);
17243efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1725c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1726c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1727c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled) {
1728c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_x >= win_left && vc->vc_x <= win_right &&
172916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		    vc->vc_y >= win_top && vc->vc_y <= win_bottom) {
17303efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs			spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1731c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return;
1732c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1733c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1734c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1735c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(str, len);
17363efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1737c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1738c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
17390012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic void speakup_con_update(struct vc_data *vc)
1740c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1741c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
17428e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1743c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_console[vc->vc_num] == NULL || spk_parked)
1744c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
17453efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1746c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* Speakup output, discard */
1747c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1748c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_date(vc);
17493efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1750c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1751c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1752c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1753c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1754c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
1755c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int on_off = 2;
1756c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *label;
17578e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1758c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL || up_flag || spk_killed)
1759c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
17603efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
1761c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
1762ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_no_intr)
1763ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
1764c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (value) {
1765c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_CAPS):
1766ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1767079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1768c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1769c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_NUM):
1770ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1771079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1772c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1773c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KVAL(K_HOLD):
1774ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1775079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1776c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_console[vc->vc_num])
1777c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_console[vc->vc_num]->tty_stopped = on_off;
1778c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
1779c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	default:
1780c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
17813efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs		spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1782c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1783c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1784c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (on_off < 2)
1785c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		synth_printf("%s %s\n",
1786ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			     label, spk_msg_get(MSG_STATUS_START + on_off));
17873efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1788c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1789c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
179016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic int inc_dec_var(u_char value)
1791c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1792c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct st_var_header *p_header;
1793c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *var_data;
1794c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char num_buf[32];
1795c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp = num_buf;
1796c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *pn;
1797c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int var_id = (int)value - VAR_START;
179816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	int how = (var_id & 1) ? E_INC : E_DEC;
17998e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
180016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	var_id = var_id / 2 + FIRST_SET_VAR;
1801ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	p_header = spk_get_var_header(var_id);
1802c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (p_header == NULL)
1803c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1804c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (p_header->var_type != VAR_NUM)
1805c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1806c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	var_data = p_header->data;
1807ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_set_num_var(1, p_header, how) != 0)
1808c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return -1;
1809c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_close_press) {
1810c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		for (pn = p_header->name; *pn; pn++) {
1811c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (*pn == '_')
1812c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				*cp = SPACE;
1813c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			else
1814c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				*cp++ = *pn;
1815c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1816c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1817c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
181816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		 var_data->u.n.value);
1819c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s", num_buf);
1820c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 0;
1821c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1822c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
182316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_set(struct vc_data *vc)
1824c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1825c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char info[40];
18268e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1827c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start > 1) {
1828ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1829c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1830c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1831c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_x < win_left || spk_y < win_top) {
1832ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1833c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1834c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1835c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start && spk_x == win_left && spk_y == win_top) {
1836c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		win_left = 0;
183716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		win_right = vc->vc_cols - 1;
1838c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		win_bottom = spk_y;
1839ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
184016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 (int)win_top + 1);
1841c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1842c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!win_start) {
1843c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_top = spk_y;
1844c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_left = spk_x;
1845c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else {
1846c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_bottom = spk_y;
1847c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			win_right = spk_x;
1848c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
1849ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1850ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			 (win_start) ? spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
185116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			 (int)spk_y + 1, (int)spk_x + 1);
1852c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1853c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_printf("%s\n", info);
1854c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_start++;
1855c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1856c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
185716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_clear(struct vc_data *vc)
1858c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1859c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_top = win_bottom = 0;
1860c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_left = win_right = 0;
1861c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_start = 0;
1862ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1863c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1864c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
186516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_win_enable(struct vc_data *vc)
1866c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1867c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_start < 2) {
1868ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1869c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1870c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1871c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	win_enabled ^= 1;
1872c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (win_enabled)
1873ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1874c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1875ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1876c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1877c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
187816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_bits(struct vc_data *vc)
1879c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1880c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
18818e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
1882ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_special_handler != NULL || val < 1 || val > 6) {
1883ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1884c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1885c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1886ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	pb_edit = &spk_punc_info[val];
1887ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1888ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_special_handler = edit_bits;
1889c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1890c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1891c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1892c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
18934ea418b8b2fa8a70d0fcc8231b65e67b3a72984bChristopher Brannon	static u_char goto_buf[8];
189416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int num;
1895ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn	int maxlen;
1896c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	char *cp;
1897ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn
1898c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1899c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto do_goto;
1900c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type == KT_LATIN && ch == '\n')
1901c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto do_goto;
1902c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type != 0)
1903c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1904c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch == 8) {
1905c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (num == 0)
1906c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			return -1;
1907c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ch = goto_buf[--num];
1908c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_buf[num] = '\0';
1909c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spkup_write(&ch, 1);
1910c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1911c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1912c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch < '+' || ch > 'y')
1913c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1914c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	goto_buf[num++] = ch;
1915c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	goto_buf[num] = '\0';
1916c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spkup_write(&ch, 1);
1917c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	maxlen = (*goto_buf >= '0') ? 3 : 4;
1918c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((ch == '+' || ch == '-') && num == 1)
1919c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1920c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch >= '0' && ch <= '9' && num < maxlen)
1921c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
192216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (num < maxlen - 1 || num > maxlen)
1923c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto oops;
1924c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (ch < 'x' || ch > 'y') {
1925c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsoops:
1926c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (!spk_killed)
1927ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1928c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_buf[num = 0] = '\0';
1929ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_special_handler = NULL;
1930c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 1;
1931c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1932ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn
1933ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn	goto_pos = simple_strtoul(goto_buf, &cp, 10);
1934ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn
1935c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (*cp == 'x') {
1936c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*goto_buf < '0')
1937c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos += spk_x;
1938ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn		else if (goto_pos > 0)
1939c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos--;
1940ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn
1941c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos >= vc->vc_cols)
194216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			goto_pos = vc->vc_cols - 1;
1943c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_x = 1;
1944c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1945c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (*goto_buf < '0')
1946c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos += spk_y;
1947ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn		else if (goto_pos > 0)
1948c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto_pos--;
1949ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98Daeseok Youn
1950c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (goto_pos >= vc->vc_rows)
195116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			goto_pos = vc->vc_rows - 1;
1952c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto_x = 0;
1953c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
195416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	goto_buf[num = 0] = '\0';
1955c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsdo_goto:
1956ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_special_handler = NULL;
1957c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_parked |= 0x01;
1958c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (goto_x) {
1959c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos -= spk_x * 2;
1960c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_x = goto_pos;
1961c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos += goto_pos * 2;
1962c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_word(vc);
1963c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
1964c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_y = goto_pos;
1965c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
1966c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		say_line(vc);
1967c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1968c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return 1;
1969c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1970c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
197116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_goto(struct vc_data *vc)
1972c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1973ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_special_handler != NULL) {
1974ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1975c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
1976c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
1977ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	synth_printf("%s\n", spk_msg_get(MSG_GOTO));
1978ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_special_handler = handle_goto;
1979c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1980c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
1981c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void speakup_help(struct vc_data *vc)
1982c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1983ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
1984c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
1985c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
198616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void do_nothing(struct vc_data *vc)
1987c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
198816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	return;			/* flush done in do_spkup */
1989c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
199016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs
1991c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic u_char key_speakup, spk_key_locked;
1992c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
199316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbsstatic void speakup_lock(struct vc_data *vc)
1994c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
1995c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (!spk_key_locked)
1996c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_key_locked = key_speakup = 16;
1997c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	else
1998c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_key_locked = key_speakup = 0;
1999c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2000c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
200116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbstypedef void (*spkup_hand) (struct vc_data *);
20020012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic spkup_hand spkup_handler[] = {
2003c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* must be ordered same as defines in speakup.h */
2004c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2005c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_cut, speakup_paste, say_first_char, say_last_char,
2006c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char, say_prev_char, say_next_char,
2007c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_word, say_prev_word, say_next_word,
2008c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_line, say_prev_line, say_next_line,
2009c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	top_edge, bottom_edge, left_edge, right_edge,
2010c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spell_word, spell_word, say_screen,
2011c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_position, say_attributes,
201216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	speakup_off, speakup_parked, say_line,	/* this is for indent */
2013c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_from_top, say_to_bottom,
2014c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_from_left, say_to_right,
2015c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2016c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_bits, speakup_bits, speakup_bits,
2017c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2018c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2019c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs};
2020c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2021c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void do_spkup(struct vc_data *vc, u_char value)
2022c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2023c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (spk_killed && value != SPEECH_KILL)
2024c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return;
2025c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_keydown = 0;
2026c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_lastkey = 0;
2027c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
2028c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	this_speakup_key = value;
2029c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2030ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		spk_do_flush();
203116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		(*spkup_handler[value]) (vc);
2032c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	} else {
2033c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (inc_dec_var(value) < 0)
2034c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(9);
2035c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2036c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2037c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2038c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic const char *pad_chars = "0123456789+-*/\015,.?()";
2039c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
20400012196c165d5158a128e2accd2e511a306a6aa7Sachin Kamatstatic int
2041c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsspeakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
204216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    int up_flag)
2043c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2044c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unsigned long flags;
2045c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int kh;
2046c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char *key_info;
2047c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2048c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	u_char shift_info, offset;
2049c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret = 0;
20508e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
2051c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (synth == NULL)
2052c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return 0;
2053c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
20543efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_lock_irqsave(&speakup_info.spinlock, flags);
20555b19208a5e236b26357162d6a28ff9e8d4296725Greg Kroah-Hartman	tty = vc->port.tty;
2056c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (type >= 0xf0)
2057c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		type -= 0xf0;
205816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	if (type == KT_PAD
2059079c9534a96da9a85a2a2f9715851050fbfbf749Alan Cox		&& (vt_get_leds(fg_console, VC_NUMLOCK))) {
2060c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (up_flag) {
2061c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			spk_keydown = 0;
2062c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			goto out;
2063c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2064c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		value = spk_lastkey = pad_chars[value];
2065c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_keydown++;
2066c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_parked &= 0xfe;
2067c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2068c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2069c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (keycode >= MAX_KEY)
2070c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2071ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	key_info = spk_our_keys[keycode];
2072ff471ea823d8cdd790759febc358c3776a90c922Sachin Kamat	if (!key_info)
2073c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto no_map;
2074c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/* Check valid read all mode keys */
2075c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((cursor_track == read_all_mode) && (!up_flag)) {
2076c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		switch (value) {
2077c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_DOWN):
2078c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_UP):
2079c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_LEFT):
2080c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_RIGHT):
2081c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_PGUP):
2082c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		case KVAL(K_PGDN):
2083c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2084c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		default:
2085c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			stop_read_all(vc);
2086c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2087c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2088c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
208916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	shift_info = (shift_state & 0x0f) + key_speakup;
2090ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	offset = spk_shift_table[shift_info];
2091c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (offset) {
2092c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		new_key = key_info[offset];
2093c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (new_key) {
2094c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ret = 1;
2095c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (new_key == SPK_KEY) {
2096c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (!spk_key_locked)
2097c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					key_speakup = (up_flag) ? 0 : 16;
2098c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (up_flag || spk_killed)
2099c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					goto out;
2100c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				spk_shut_up &= 0xfe;
2101ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				spk_do_flush();
2102c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				goto out;
2103c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
2104c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (up_flag)
2105c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				goto out;
2106c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			if (last_keycode == keycode &&
21073d3cb1bffde15ee6e69532457bee20b5d424952bRobin Schroer			    time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2108c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				spk_close_press = 1;
2109ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault				offset = spk_shift_table[shift_info + 32];
211016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				/* double press? */
2111c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs				if (offset && key_info[offset])
2112c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs					new_key = key_info[offset];
2113c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			}
2114c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_keycode = keycode;
2115c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			last_spk_jiffy = jiffies;
2116c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_SPKUP;
2117c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			value = new_key;
2118c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2119c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2120c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsno_map:
2121ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (type == KT_SPKUP && spk_special_handler == NULL) {
2122c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		do_spkup(vc, new_key);
2123c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_close_press = 0;
2124c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		ret = 1;
2125c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2126c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2127c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (up_flag || spk_killed || type == KT_SHIFT)
2128c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2129c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_shut_up &= 0xfe;
2130c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	kh = (value == KVAL(K_DOWN))
213116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_UP))
213216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_LEFT))
213316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	    || (value == KVAL(K_RIGHT));
2134c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if ((cursor_track != read_all_mode) || !kh)
2135ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if (!spk_no_intr)
2136ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			spk_do_flush();
2137ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_special_handler) {
2138c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (type == KT_SPEC && value == 1) {
2139c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			value = '\n';
2140c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_LATIN;
2141c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		} else if (type == KT_LETTER)
2142c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			type = KT_LATIN;
2143c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		else if (value == 0x7f)
214416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			value = 8;	/* make del = backspace */
2145ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		ret = (*spk_special_handler) (vc, type, value, keycode);
2146c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		spk_close_press = 0;
2147c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (ret < 0)
2148c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			bleep(9);
2149c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		goto out;
2150c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2151c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	last_keycode = 0;
2152c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsout:
21533efe810f2322223eca3b3a1dea3ae40500cbd471William Hubbs	spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2154c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ret;
2155c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2156c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2157c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int keyboard_notifier_call(struct notifier_block *nb,
215816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				  unsigned long code, void *_param)
2159c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2160c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct keyboard_notifier_param *param = _param;
2161c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = param->vc;
2162c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int up = !param->down;
2163c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int ret = NOTIFY_OK;
216416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	static int keycode;	/* to hold the current keycode */
2165c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2166c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (vc->vc_mode == KD_GRAPHICS)
2167c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return ret;
2168c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2169c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	/*
2170c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * First, determine whether we are handling a fake keypress on
2171c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * the current processor.  If we are, then return NOTIFY_OK,
2172c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * to pass the keystroke up the chain.  This prevents us from
2173c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * trying to take the Speakup lock while it is held by the
2174c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * processor on which the simulated keystroke was generated.
2175c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 * Also, the simulated keystrokes should be ignored by Speakup.
2176c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	 */
2177c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2178c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	if (speakup_fake_key_pressed())
2179c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		return ret;
2180c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2181c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (code) {
2182c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_KEYCODE:
2183c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* speakup requires keycode and keysym currently */
2184c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		keycode = param->value;
2185c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2186c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_UNBOUND_KEYCODE:
2187c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* not used yet */
2188c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2189c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_UNICODE:
2190c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		/* not used yet */
2191c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2192c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case KBD_KEYSYM:
2193c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (speakup_key(vc, param->shift, keycode, param->value, up))
2194c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			ret = NOTIFY_STOP;
219516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		else if (KTYP(param->value) == KT_CUR)
219616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			ret = pre_handle_cursor(vc, KVAL(param->value), up);
2197c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
219816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	case KBD_POST_KEYSYM:{
219916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			unsigned char type = KTYP(param->value) - 0xf0;
220016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			unsigned char val = KVAL(param->value);
22018e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
220216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			switch (type) {
220316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_SHIFT:
220416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_shift(vc, val, up);
220516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
220616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_LATIN:
220716d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_LETTER:
220816d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_latin(vc, val, up);
220916d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
221016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_CUR:
221116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_cursor(vc, val, up);
221216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
221316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			case KT_SPEC:
221416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				do_handle_spec(vc, val, up);
221516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs				break;
221616d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			}
2217c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			break;
2218c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		}
2219c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2220c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return ret;
2221c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2222c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2223c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int vt_notifier_call(struct notifier_block *nb,
222416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			    unsigned long code, void *_param)
2225c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2226c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vt_notifier_param *param = _param;
2227c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = param->vc;
22288e69a8110686572a4b88d006faa8c3c759c4c261Domagoj Trsan
2229c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	switch (code) {
2230c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_ALLOCATE:
2231c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (vc->vc_mode == KD_TEXT)
2232c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_allocate(vc);
2233c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2234c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_DEALLOCATE:
2235c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_deallocate(vc);
2236c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2237c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_WRITE:
2238c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		if (param->c == '\b')
2239c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs			speakup_bs(vc);
224016d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		else if (param->c < 0x100) {
224116d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			char d = param->c;
22420a3a725adb2c421ea79089ea12004a007fb371ceRoxana Blaj
224316d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs			speakup_con_write(vc, &d, 1);
224416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs		}
2245c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2246c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	case VT_UPDATE:
2247c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_con_update(vc);
2248c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		break;
2249c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2250c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	return NOTIFY_OK;
2251c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2252c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2253c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* called by: module_exit() */
2254c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic void __exit speakup_exit(void)
2255c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2256c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
2257c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2258c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unregister_keyboard_notifier(&keyboard_notifier_block);
2259c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	unregister_vt_notifier(&vt_notifier_block);
2260c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_unregister_devsynth();
2261d7500135802ca55b3f4e01a16544e8b34082f8c3Ben Hutchings	speakup_cancel_paste();
2262c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	del_timer(&cursor_timer);
2263c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	kthread_stop(speakup_task);
2264c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_task = NULL;
2265c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mutex_lock(&spk_mutex);
2266c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_release();
2267c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	mutex_unlock(&spk_mutex);
2268c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2269628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_kobj_exit();
2270628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2271628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAX_NR_CONSOLES; i++)
2272628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		kfree(speakup_console[i]);
2273628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2274628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_remove_virtual_keyboard();
2275628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2276c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < MAXVARS; i++)
2277c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_unregister_var(i);
2278c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2279c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < 256; i++) {
2280ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if (spk_characters[i] != spk_default_chars[i])
2281ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			kfree(spk_characters[i]);
2282c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	}
2283628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2284ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_free_user_msgs();
2285c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2286c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2287c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs/* call by: module_init() */
2288c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsstatic int __init speakup_init(void)
2289c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs{
2290c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	int i;
2291628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	long err = 0;
2292c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct st_spk_t *first_console;
2293c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct vc_data *vc = vc_cons[fg_console].d;
2294c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	struct var_t *var;
2295c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2296628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/* These first few initializations cannot fail. */
2297ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_initialize_msgs();	/* Initialize arrays for i18n. */
2298ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_reset_default_chars();
2299ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_reset_default_chartab();
2300ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_strlwr(synth_name);
2301c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	spk_vars[0].u.n.high = vc->vc_cols;
230216d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (var = spk_vars; var->var_id != MAXVARS; var++)
2303c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_register_var(var);
230416d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	for (var = synth_time_vars;
230516d355156ba475c0fefb19133174cdf61a5101baWilliam Hubbs	     (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2306c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs		speakup_register_var(var);
2307ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	for (i = 1; spk_punc_info[i].mask != 0; i++)
2308ff471ea823d8cdd790759febc358c3776a90c922Sachin Kamat		spk_set_mask_bits(NULL, i, 2);
2309c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2310ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_set_key_info(spk_key_defaults, spk_key_buf);
2311c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2312628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/* From here on out, initializations can fail. */
2313628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = speakup_add_virtual_keyboard();
2314628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2315628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_virtkeyboard;
2316628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2317628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	first_console = kzalloc(sizeof(*first_console), GFP_KERNEL);
2318628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (!first_console) {
2319628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		err = -ENOMEM;
2320628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_alloc;
2321628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	}
2322628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2323628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_console[vc->vc_num] = first_console;
2324628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_date(vc);
2325628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2326c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	for (i = 0; i < MAX_NR_CONSOLES; i++)
2327628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		if (vc_cons[i].d) {
2328628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			err = speakup_allocate(vc_cons[i].d);
2329628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon			if (err)
2330628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon				goto error_kobjects;
2331628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		}
2332628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2333ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	if (spk_quiet_boot)
23344afaee1561e207683dbb886b30a842ffcc22e366Christopher Brannon		spk_shut_up |= 0x01;
23354afaee1561e207683dbb886b30a842ffcc22e366Christopher Brannon
2336628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = speakup_kobj_init();
2337628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2338628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_kobjects;
2339c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2340c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	synth_init(synth_name);
2341c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_register_devsynth();
2342628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	/*
2343628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * register_devsynth might fail, but this error is not fatal.
2344628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * /dev/synth is an extra feature; the rest of Speakup
2345628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 * will work fine without it.
2346628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	 */
2347c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2348628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = register_keyboard_notifier(&keyboard_notifier_block);
2349628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2350628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_kbdnotifier;
2351628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	err = register_vt_notifier(&vt_notifier_block);
2352628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	if (err)
2353628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_vtnotifier;
2354c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2355c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs	speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2356628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
23577959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	if (IS_ERR(speakup_task)) {
2358628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		err = PTR_ERR(speakup_task);
2359628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		goto error_task;
23607959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	}
2361628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2362628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	set_user_nice(speakup_task, 10);
23637959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	wake_up_process(speakup_task);
2364628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2365628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2366628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	pr_info("synth name on entry is: %s\n", synth_name);
23677959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	goto out;
23687959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs
2369628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_task:
2370628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	unregister_vt_notifier(&vt_notifier_block);
2371628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2372628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_vtnotifier:
2373628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	unregister_keyboard_notifier(&keyboard_notifier_block);
2374628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	del_timer(&cursor_timer);
2375628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2376628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_kbdnotifier:
2377628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_unregister_devsynth();
2378628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	mutex_lock(&spk_mutex);
2379628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	synth_release();
2380628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	mutex_unlock(&spk_mutex);
2381628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	speakup_kobj_exit();
2382628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2383628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_kobjects:
2384628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAX_NR_CONSOLES; i++)
2385628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		kfree(speakup_console[i]);
2386628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2387628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_alloc:
23887959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	speakup_remove_virtual_keyboard();
2389628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2390628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannonerror_virtkeyboard:
2391628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < MAXVARS; i++)
2392628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon		speakup_unregister_var(i);
2393628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2394628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	for (i = 0; i < 256; i++) {
2395ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault		if (spk_characters[i] != spk_default_chars[i])
2396ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault			kfree(spk_characters[i]);
2397628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon	}
2398628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
2399ca2beaf84d9678c12b17d92623f0e90829d6ca13Samuel Thibault	spk_free_user_msgs();
2400628f34282db49359576dcb8cbaea65b4bf083ebdChristopher Brannon
24017959d55679e4360205c9ebc89d40a5503c53bae2William Hubbsout:
24027959d55679e4360205c9ebc89d40a5503c53bae2William Hubbs	return err;
2403c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs}
2404c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbs
2405c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_init(speakup_init);
2406c6e3fd22cd538365bfeb82997d5b89562e077d42William Hubbsmodule_exit(speakup_exit);
2407