0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/kernel.h>
0013 #include <linux/vt.h>
0014 #include <linux/tty.h>
0015 #include <linux/mm.h> /* __get_free_page() and friends */
0016 #include <linux/vt_kern.h>
0017 #include <linux/ctype.h>
0018 #include <linux/selection.h>
0019 #include <linux/unistd.h>
0020 #include <linux/jiffies.h>
0021 #include <linux/kthread.h>
0022 #include <linux/keyboard.h> /* for KT_SHIFT */
0023 #include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
0024 #include <linux/input.h>
0025 #include <linux/kmod.h>
0026
0027
0028 #include <linux/module.h>
0029 #include <linux/sched.h>
0030 #include <linux/slab.h>
0031 #include <linux/types.h>
0032 #include <linux/consolemap.h>
0033
0034 #include <linux/spinlock.h>
0035 #include <linux/notifier.h>
0036
0037 #include <linux/uaccess.h> /* copy_from|to|user() and others */
0038
0039 #include "spk_priv.h"
0040 #include "speakup.h"
0041
0042 #define MAX_DELAY msecs_to_jiffies(500)
0043 #define MINECHOCHAR SPACE
0044
0045 MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
0046 MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
0047 MODULE_DESCRIPTION("Speakup console speech");
0048 MODULE_LICENSE("GPL");
0049 MODULE_VERSION(SPEAKUP_VERSION);
0050
0051 char *synth_name;
0052 module_param_named(synth, synth_name, charp, 0444);
0053 module_param_named(quiet, spk_quiet_boot, bool, 0444);
0054
0055 MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
0056 MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
0057
0058 special_func spk_special_handler;
0059
0060 short spk_pitch_shift, synth_flags;
0061 static u16 buf[256];
0062 int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
0063 int spk_no_intr, spk_spell_delay;
0064 int spk_key_echo, spk_say_word_ctl;
0065 int spk_say_ctrl, spk_bell_pos;
0066 short spk_punc_mask;
0067 int spk_punc_level, spk_reading_punc;
0068 char spk_str_caps_start[MAXVARLEN + 1] = "\0";
0069 char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
0070 char spk_str_pause[MAXVARLEN + 1] = "\0";
0071 bool spk_paused;
0072 const struct st_bits_data spk_punc_info[] = {
0073 {"none", "", 0},
0074 {"some", "/$%&@", SOME},
0075 {"most", "$%&#()=+*/@^<>|\\", MOST},
0076 {"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
0077 {"delimiters", "", B_WDLM},
0078 {"repeats", "()", CH_RPT},
0079 {"extended numeric", "", B_EXNUM},
0080 {"symbols", "", B_SYM},
0081 {NULL, NULL}
0082 };
0083
0084 static char mark_cut_flag;
0085 #define MAX_KEY 160
0086 static u_char *spk_shift_table;
0087 u_char *spk_our_keys[MAX_KEY];
0088 u_char spk_key_buf[600];
0089 const u_char spk_key_defaults[] = {
0090 #include "speakupmap.h"
0091 };
0092
0093
0094 enum cursor_track {
0095 CT_Off = 0,
0096 CT_On,
0097 CT_Highlight,
0098 CT_Window,
0099 CT_Max,
0100 read_all_mode = CT_Max,
0101 };
0102
0103
0104 static enum cursor_track cursor_track = 1, prev_cursor_track = 1;
0105
0106 static struct tty_struct *tty;
0107
0108 static void spkup_write(const u16 *in_buf, int count);
0109
0110 static char *phonetic[] = {
0111 "alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
0112 "india", "juliett", "keelo", "leema", "mike", "november", "oscar",
0113 "papa",
0114 "keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
0115 "x ray", "yankee", "zulu"
0116 };
0117
0118
0119
0120
0121
0122 char *spk_characters[256];
0123
0124 char *spk_default_chars[256] = {
0125 "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
0126 "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
0127 "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
0128 "^x", "^y", "^z", "control", "control", "control", "control",
0129 "control",
0130 "space", "bang!", "quote", "number", "dollar", "percent", "and",
0131 "tick",
0132 "left paren", "right paren", "star", "plus", "comma", "dash",
0133 "dot",
0134 "slash",
0135 "zero", "one", "two", "three", "four", "five", "six", "seven",
0136 "eight", "nine",
0137 "colon", "semmy", "less", "equals", "greater", "question", "at",
0138 "EIGH", "B", "C", "D", "E", "F", "G",
0139 "H", "I", "J", "K", "L", "M", "N", "O",
0140 "P", "Q", "R", "S", "T", "U", "V", "W", "X",
0141 "Y", "ZED", "left bracket", "backslash", "right bracket",
0142 "caret",
0143 "line",
0144 "accent", "a", "b", "c", "d", "e", "f", "g",
0145 "h", "i", "j", "k", "l", "m", "n", "o",
0146 "p", "q", "r", "s", "t", "u", "v", "w",
0147 "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
0148 "del", "control", "control", "control", "control", "control",
0149 "control", "control", "control", "control", "control",
0150 "control", "control", "control", "control", "control",
0151 "control", "control", "control", "control", "control",
0152 "control", "control",
0153 "control", "control", "control", "control", "control",
0154 "control", "control", "control", "control", "control",
0155 "nbsp", "inverted bang",
0156 "cents", "pounds", "currency", "yen", "broken bar", "section",
0157 "diaeresis", "copyright", "female ordinal", "double left angle",
0158 "not", "soft hyphen", "registered", "macron",
0159 "degrees", "plus or minus", "super two", "super three",
0160 "acute accent", "micro", "pilcrow", "middle dot",
0161 "cedilla", "super one", "male ordinal", "double right angle",
0162 "one quarter", "one half", "three quarters",
0163 "inverted question",
0164 "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
0165 "A RING",
0166 "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
0167 "E OOMLAUT",
0168 "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
0169 "N TILDE",
0170 "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
0171 "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
0172 "U CIRCUMFLEX",
0173 "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
0174 "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
0175 "ae", "c cidella", "e grave", "e acute",
0176 "e circumflex", "e oomlaut", "i grave", "i acute",
0177 "i circumflex",
0178 "i oomlaut", "eth", "n tilde", "o grave", "o acute",
0179 "o circumflex",
0180 "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
0181 "u acute",
0182 "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
0183 };
0184
0185
0186
0187
0188
0189 u_short spk_chartab[256];
0190
0191 static u_short default_chartab[256] = {
0192 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,
0193 B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,
0194 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,
0195 B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL,
0196 WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,
0197 PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC,
0198 NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM,
0199 NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC,
0200 PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,
0201 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,
0202 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,
0203 A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC,
0204 PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,
0205 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,
0206 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,
0207 ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0,
0208 B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,
0209 B_SYM,
0210 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,
0211 B_CAPSYM,
0212 B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM,
0213 B_SYM,
0214 B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM,
0215 B_SYM,
0216 WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM,
0217 B_SYM,
0218 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,
0219 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,
0220 B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM,
0221 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,
0222 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP,
0223 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM,
0224 A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA,
0225 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,
0226 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,
0227 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM,
0228 ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA
0229 };
0230
0231 struct task_struct *speakup_task;
0232 struct bleep spk_unprocessed_sound;
0233 static int spk_keydown;
0234 static u16 spk_lastkey;
0235 static u_char spk_close_press, keymap_flags;
0236 static u_char last_keycode, this_speakup_key;
0237 static u_long last_spk_jiffy;
0238
0239 struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
0240
0241 DEFINE_MUTEX(spk_mutex);
0242
0243 static int keyboard_notifier_call(struct notifier_block *,
0244 unsigned long code, void *param);
0245
0246 static struct notifier_block keyboard_notifier_block = {
0247 .notifier_call = keyboard_notifier_call,
0248 };
0249
0250 static int vt_notifier_call(struct notifier_block *,
0251 unsigned long code, void *param);
0252
0253 static struct notifier_block vt_notifier_block = {
0254 .notifier_call = vt_notifier_call,
0255 };
0256
0257 static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
0258 {
0259 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
0260 return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
0261 }
0262
0263 static void speakup_date(struct vc_data *vc)
0264 {
0265 spk_x = spk_cx = vc->state.x;
0266 spk_y = spk_cy = vc->state.y;
0267 spk_pos = spk_cp = vc->vc_pos;
0268 spk_old_attr = spk_attr;
0269 spk_attr = get_attributes(vc, (u_short *)spk_pos);
0270 }
0271
0272 static void bleep(u_short val)
0273 {
0274 static const short vals[] = {
0275 350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
0276 };
0277 short freq;
0278 int time = spk_bleep_time;
0279
0280 freq = vals[val % 12];
0281 if (val > 11)
0282 freq *= (1 << (val / 12));
0283 spk_unprocessed_sound.freq = freq;
0284 spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
0285 spk_unprocessed_sound.active = 1;
0286
0287 }
0288
0289 static void speakup_shut_up(struct vc_data *vc)
0290 {
0291 if (spk_killed)
0292 return;
0293 spk_shut_up |= 0x01;
0294 spk_parked &= 0xfe;
0295 speakup_date(vc);
0296 if (synth)
0297 spk_do_flush();
0298 }
0299
0300 static void speech_kill(struct vc_data *vc)
0301 {
0302 char val = synth->is_alive(synth);
0303
0304 if (val == 0)
0305 return;
0306
0307
0308 if (val == 2 || spk_killed) {
0309
0310 spk_shut_up &= ~0x40;
0311 synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
0312 } else {
0313 synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
0314 spk_shut_up |= 0x40;
0315 }
0316 }
0317
0318 static void speakup_off(struct vc_data *vc)
0319 {
0320 if (spk_shut_up & 0x80) {
0321 spk_shut_up &= 0x7f;
0322 synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
0323 } else {
0324 spk_shut_up |= 0x80;
0325 synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
0326 }
0327 speakup_date(vc);
0328 }
0329
0330 static void speakup_parked(struct vc_data *vc)
0331 {
0332 if (spk_parked & 0x80) {
0333 spk_parked = 0;
0334 synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
0335 } else {
0336 spk_parked |= 0x80;
0337 synth_printf("%s\n", spk_msg_get(MSG_PARKED));
0338 }
0339 }
0340
0341 static void speakup_cut(struct vc_data *vc)
0342 {
0343 static const char err_buf[] = "set selection failed";
0344 int ret;
0345
0346 if (!mark_cut_flag) {
0347 mark_cut_flag = 1;
0348 spk_xs = (u_short)spk_x;
0349 spk_ys = (u_short)spk_y;
0350 spk_sel_cons = vc;
0351 synth_printf("%s\n", spk_msg_get(MSG_MARK));
0352 return;
0353 }
0354 spk_xe = (u_short)spk_x;
0355 spk_ye = (u_short)spk_y;
0356 mark_cut_flag = 0;
0357 synth_printf("%s\n", spk_msg_get(MSG_CUT));
0358
0359 ret = speakup_set_selection(tty);
0360
0361 switch (ret) {
0362 case 0:
0363 break;
0364 case -EFAULT:
0365 pr_warn("%sEFAULT\n", err_buf);
0366 break;
0367 case -EINVAL:
0368 pr_warn("%sEINVAL\n", err_buf);
0369 break;
0370 case -ENOMEM:
0371 pr_warn("%sENOMEM\n", err_buf);
0372 break;
0373 }
0374 }
0375
0376 static void speakup_paste(struct vc_data *vc)
0377 {
0378 if (mark_cut_flag) {
0379 mark_cut_flag = 0;
0380 synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
0381 } else {
0382 synth_printf("%s\n", spk_msg_get(MSG_PASTE));
0383 speakup_paste_selection(tty);
0384 }
0385 }
0386
0387 static void say_attributes(struct vc_data *vc)
0388 {
0389 int fg = spk_attr & 0x0f;
0390 int bg = spk_attr >> 4;
0391
0392 synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
0393 if (bg > 7) {
0394 synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
0395 bg -= 8;
0396 } else {
0397 synth_printf(" %s ", spk_msg_get(MSG_ON));
0398 }
0399 synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
0400 }
0401
0402
0403 enum edge {
0404 edge_none = 0,
0405 edge_top,
0406 edge_bottom,
0407 edge_left,
0408 edge_right,
0409 edge_quiet
0410 };
0411
0412 static void announce_edge(struct vc_data *vc, enum edge msg_id)
0413 {
0414 if (spk_bleeps & 1)
0415 bleep(spk_y);
0416 if ((spk_bleeps & 2) && (msg_id < edge_quiet))
0417 synth_printf("%s\n",
0418 spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
0419 }
0420
0421 static void speak_char(u16 ch)
0422 {
0423 char *cp;
0424 struct var_t *direct = spk_get_var(DIRECT);
0425
0426 if (ch >= 0x100 || (direct && direct->u.n.value)) {
0427 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
0428 spk_pitch_shift++;
0429 synth_printf("%s", spk_str_caps_start);
0430 }
0431 synth_putwc_s(ch);
0432 if (ch < 0x100 && IS_CHAR(ch, B_CAP))
0433 synth_printf("%s", spk_str_caps_stop);
0434 return;
0435 }
0436
0437 cp = spk_characters[ch];
0438 if (!cp) {
0439 pr_info("%s: cp == NULL!\n", __func__);
0440 return;
0441 }
0442 if (IS_CHAR(ch, B_CAP)) {
0443 spk_pitch_shift++;
0444 synth_printf("%s %s %s",
0445 spk_str_caps_start, cp, spk_str_caps_stop);
0446 } else {
0447 if (*cp == '^') {
0448 cp++;
0449 synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
0450 } else {
0451 synth_printf(" %s ", cp);
0452 }
0453 }
0454 }
0455
0456 static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
0457 {
0458 u16 ch = ' ';
0459
0460 if (vc && pos) {
0461 u16 w;
0462 u16 c;
0463
0464 pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
0465 w = scr_readw(pos);
0466 c = w & 0xff;
0467
0468 if (w & vc->vc_hi_font_mask) {
0469 w &= ~vc->vc_hi_font_mask;
0470 c |= 0x100;
0471 }
0472
0473 ch = inverse_translate(vc, c, true);
0474 *attribs = (w & 0xff00) >> 8;
0475 }
0476 return ch;
0477 }
0478
0479 static void say_char(struct vc_data *vc)
0480 {
0481 u16 ch;
0482
0483 spk_old_attr = spk_attr;
0484 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
0485 if (spk_attr != spk_old_attr) {
0486 if (spk_attrib_bleep & 1)
0487 bleep(spk_y);
0488 if (spk_attrib_bleep & 2)
0489 say_attributes(vc);
0490 }
0491 speak_char(ch);
0492 }
0493
0494 static void say_phonetic_char(struct vc_data *vc)
0495 {
0496 u16 ch;
0497
0498 spk_old_attr = spk_attr;
0499 ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
0500 if (ch <= 0x7f && isalpha(ch)) {
0501 ch &= 0x1f;
0502 synth_printf("%s\n", phonetic[--ch]);
0503 } else {
0504 if (ch < 0x100 && IS_CHAR(ch, B_NUM))
0505 synth_printf("%s ", spk_msg_get(MSG_NUMBER));
0506 speak_char(ch);
0507 }
0508 }
0509
0510 static void say_prev_char(struct vc_data *vc)
0511 {
0512 spk_parked |= 0x01;
0513 if (spk_x == 0) {
0514 announce_edge(vc, edge_left);
0515 return;
0516 }
0517 spk_x--;
0518 spk_pos -= 2;
0519 say_char(vc);
0520 }
0521
0522 static void say_next_char(struct vc_data *vc)
0523 {
0524 spk_parked |= 0x01;
0525 if (spk_x == vc->vc_cols - 1) {
0526 announce_edge(vc, edge_right);
0527 return;
0528 }
0529 spk_x++;
0530 spk_pos += 2;
0531 say_char(vc);
0532 }
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542
0543 static u_long get_word(struct vc_data *vc)
0544 {
0545 u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
0546 u16 ch;
0547 u16 attr_ch;
0548 u_char temp;
0549
0550 spk_old_attr = spk_attr;
0551 ch = get_char(vc, (u_short *)tmp_pos, &temp);
0552
0553
0554 if (spk_say_word_ctl && ch == SPACE) {
0555 *buf = '\0';
0556 synth_printf("%s\n", spk_msg_get(MSG_SPACE));
0557 return 0;
0558 } else if (tmpx < vc->vc_cols - 2 &&
0559 (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
0560 get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
0561 tmp_pos += 2;
0562 tmpx++;
0563 } else {
0564 while (tmpx > 0) {
0565 ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
0566 if ((ch == SPACE || ch == 0 ||
0567 (ch < 0x100 && IS_WDLM(ch))) &&
0568 get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
0569 break;
0570 tmp_pos -= 2;
0571 tmpx--;
0572 }
0573 }
0574 attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
0575 buf[cnt++] = attr_ch;
0576 while (tmpx < vc->vc_cols - 1) {
0577 tmp_pos += 2;
0578 tmpx++;
0579 ch = get_char(vc, (u_short *)tmp_pos, &temp);
0580 if (ch == SPACE || ch == 0 ||
0581 (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
0582 ch > SPACE))
0583 break;
0584 buf[cnt++] = ch;
0585 }
0586 buf[cnt] = '\0';
0587 return cnt;
0588 }
0589
0590 static void say_word(struct vc_data *vc)
0591 {
0592 u_long cnt = get_word(vc);
0593 u_short saved_punc_mask = spk_punc_mask;
0594
0595 if (cnt == 0)
0596 return;
0597 spk_punc_mask = PUNC;
0598 buf[cnt++] = SPACE;
0599 spkup_write(buf, cnt);
0600 spk_punc_mask = saved_punc_mask;
0601 }
0602
0603 static void say_prev_word(struct vc_data *vc)
0604 {
0605 u_char temp;
0606 u16 ch;
0607 enum edge edge_said = edge_none;
0608 u_short last_state = 0, state = 0;
0609
0610 spk_parked |= 0x01;
0611
0612 if (spk_x == 0) {
0613 if (spk_y == 0) {
0614 announce_edge(vc, edge_top);
0615 return;
0616 }
0617 spk_y--;
0618 spk_x = vc->vc_cols;
0619 edge_said = edge_quiet;
0620 }
0621 while (1) {
0622 if (spk_x == 0) {
0623 if (spk_y == 0) {
0624 edge_said = edge_top;
0625 break;
0626 }
0627 if (edge_said != edge_quiet)
0628 edge_said = edge_left;
0629 if (state > 0)
0630 break;
0631 spk_y--;
0632 spk_x = vc->vc_cols - 1;
0633 } else {
0634 spk_x--;
0635 }
0636 spk_pos -= 2;
0637 ch = get_char(vc, (u_short *)spk_pos, &temp);
0638 if (ch == SPACE || ch == 0)
0639 state = 0;
0640 else if (ch < 0x100 && IS_WDLM(ch))
0641 state = 1;
0642 else
0643 state = 2;
0644 if (state < last_state) {
0645 spk_pos += 2;
0646 spk_x++;
0647 break;
0648 }
0649 last_state = state;
0650 }
0651 if (spk_x == 0 && edge_said == edge_quiet)
0652 edge_said = edge_left;
0653 if (edge_said > edge_none && edge_said < edge_quiet)
0654 announce_edge(vc, edge_said);
0655 say_word(vc);
0656 }
0657
0658 static void say_next_word(struct vc_data *vc)
0659 {
0660 u_char temp;
0661 u16 ch;
0662 enum edge edge_said = edge_none;
0663 u_short last_state = 2, state = 0;
0664
0665 spk_parked |= 0x01;
0666 if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
0667 announce_edge(vc, edge_bottom);
0668 return;
0669 }
0670 while (1) {
0671 ch = get_char(vc, (u_short *)spk_pos, &temp);
0672 if (ch == SPACE || ch == 0)
0673 state = 0;
0674 else if (ch < 0x100 && IS_WDLM(ch))
0675 state = 1;
0676 else
0677 state = 2;
0678 if (state > last_state)
0679 break;
0680 if (spk_x >= vc->vc_cols - 1) {
0681 if (spk_y == vc->vc_rows - 1) {
0682 edge_said = edge_bottom;
0683 break;
0684 }
0685 state = 0;
0686 spk_y++;
0687 spk_x = 0;
0688 edge_said = edge_right;
0689 } else {
0690 spk_x++;
0691 }
0692 spk_pos += 2;
0693 last_state = state;
0694 }
0695 if (edge_said > edge_none)
0696 announce_edge(vc, edge_said);
0697 say_word(vc);
0698 }
0699
0700 static void spell_word(struct vc_data *vc)
0701 {
0702 static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
0703 u16 *cp = buf;
0704 char *cp1;
0705 char *str_cap = spk_str_caps_stop;
0706 char *last_cap = spk_str_caps_stop;
0707 struct var_t *direct = spk_get_var(DIRECT);
0708 u16 ch;
0709
0710 if (!get_word(vc))
0711 return;
0712 while ((ch = *cp)) {
0713 if (cp != buf)
0714 synth_printf(" %s ", delay_str[spk_spell_delay]);
0715
0716 if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
0717 str_cap = spk_str_caps_start;
0718 if (*spk_str_caps_stop)
0719 spk_pitch_shift++;
0720 else
0721 last_cap = spk_str_caps_stop;
0722 } else {
0723 str_cap = spk_str_caps_stop;
0724 }
0725 if (str_cap != last_cap) {
0726 synth_printf("%s", str_cap);
0727 last_cap = str_cap;
0728 }
0729 if (ch >= 0x100 || (direct && direct->u.n.value)) {
0730 synth_putwc_s(ch);
0731 } else if (this_speakup_key == SPELL_PHONETIC &&
0732 ch <= 0x7f && isalpha(ch)) {
0733 ch &= 0x1f;
0734 cp1 = phonetic[--ch];
0735 synth_printf("%s", cp1);
0736 } else {
0737 cp1 = spk_characters[ch];
0738 if (*cp1 == '^') {
0739 synth_printf("%s", spk_msg_get(MSG_CTRL));
0740 cp1++;
0741 }
0742 synth_printf("%s", cp1);
0743 }
0744 cp++;
0745 }
0746 if (str_cap != spk_str_caps_stop)
0747 synth_printf("%s", spk_str_caps_stop);
0748 }
0749
0750 static int get_line(struct vc_data *vc)
0751 {
0752 u_long tmp = spk_pos - (spk_x * 2);
0753 int i = 0;
0754 u_char tmp2;
0755
0756 spk_old_attr = spk_attr;
0757 spk_attr = get_attributes(vc, (u_short *)spk_pos);
0758 for (i = 0; i < vc->vc_cols; i++) {
0759 buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
0760 tmp += 2;
0761 }
0762 for (--i; i >= 0; i--)
0763 if (buf[i] != SPACE)
0764 break;
0765 return ++i;
0766 }
0767
0768 static void say_line(struct vc_data *vc)
0769 {
0770 int i = get_line(vc);
0771 u16 *cp;
0772 u_short saved_punc_mask = spk_punc_mask;
0773
0774 if (i == 0) {
0775 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
0776 return;
0777 }
0778 buf[i++] = '\n';
0779 if (this_speakup_key == SAY_LINE_INDENT) {
0780 cp = buf;
0781 while (*cp == SPACE)
0782 cp++;
0783 synth_printf("%zd, ", (cp - buf) + 1);
0784 }
0785 spk_punc_mask = spk_punc_masks[spk_reading_punc];
0786 spkup_write(buf, i);
0787 spk_punc_mask = saved_punc_mask;
0788 }
0789
0790 static void say_prev_line(struct vc_data *vc)
0791 {
0792 spk_parked |= 0x01;
0793 if (spk_y == 0) {
0794 announce_edge(vc, edge_top);
0795 return;
0796 }
0797 spk_y--;
0798 spk_pos -= vc->vc_size_row;
0799 say_line(vc);
0800 }
0801
0802 static void say_next_line(struct vc_data *vc)
0803 {
0804 spk_parked |= 0x01;
0805 if (spk_y == vc->vc_rows - 1) {
0806 announce_edge(vc, edge_bottom);
0807 return;
0808 }
0809 spk_y++;
0810 spk_pos += vc->vc_size_row;
0811 say_line(vc);
0812 }
0813
0814 static int say_from_to(struct vc_data *vc, u_long from, u_long to,
0815 int read_punc)
0816 {
0817 int i = 0;
0818 u_char tmp;
0819 u_short saved_punc_mask = spk_punc_mask;
0820
0821 spk_old_attr = spk_attr;
0822 spk_attr = get_attributes(vc, (u_short *)from);
0823 while (from < to) {
0824 buf[i++] = get_char(vc, (u_short *)from, &tmp);
0825 from += 2;
0826 if (i >= vc->vc_size_row)
0827 break;
0828 }
0829 for (--i; i >= 0; i--)
0830 if (buf[i] != SPACE)
0831 break;
0832 buf[++i] = SPACE;
0833 buf[++i] = '\0';
0834 if (i < 1)
0835 return i;
0836 if (read_punc)
0837 spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
0838 spkup_write(buf, i);
0839 if (read_punc)
0840 spk_punc_mask = saved_punc_mask;
0841 return i - 1;
0842 }
0843
0844 static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
0845 int read_punc)
0846 {
0847 u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
0848 u_long end = start + (to * 2);
0849
0850 start += from * 2;
0851 if (say_from_to(vc, start, end, read_punc) <= 0)
0852 if (cursor_track != read_all_mode)
0853 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
0854 }
0855
0856
0857
0858 static int currsentence;
0859 static int numsentences[2];
0860 static u16 *sentbufend[2];
0861 static u16 *sentmarks[2][10];
0862 static int currbuf;
0863 static int bn;
0864 static u16 sentbuf[2][256];
0865
0866 static int say_sentence_num(int num, int prev)
0867 {
0868 bn = currbuf;
0869 currsentence = num + 1;
0870 if (prev && --bn == -1)
0871 bn = 1;
0872
0873 if (num > numsentences[bn])
0874 return 0;
0875
0876 spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
0877 return 1;
0878 }
0879
0880 static int get_sentence_buf(struct vc_data *vc, int read_punc)
0881 {
0882 u_long start, end;
0883 int i, bn;
0884 u_char tmp;
0885
0886 currbuf++;
0887 if (currbuf == 2)
0888 currbuf = 0;
0889 bn = currbuf;
0890 start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
0891 end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
0892
0893 numsentences[bn] = 0;
0894 sentmarks[bn][0] = &sentbuf[bn][0];
0895 i = 0;
0896 spk_old_attr = spk_attr;
0897 spk_attr = get_attributes(vc, (u_short *)start);
0898
0899 while (start < end) {
0900 sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
0901 if (i > 0) {
0902 if (sentbuf[bn][i] == SPACE &&
0903 sentbuf[bn][i - 1] == '.' &&
0904 numsentences[bn] < 9) {
0905
0906 numsentences[bn]++;
0907 sentmarks[bn][numsentences[bn]] =
0908 &sentbuf[bn][i];
0909 }
0910 }
0911 i++;
0912 start += 2;
0913 if (i >= vc->vc_size_row)
0914 break;
0915 }
0916
0917 for (--i; i >= 0; i--)
0918 if (sentbuf[bn][i] != SPACE)
0919 break;
0920
0921 if (i < 1)
0922 return -1;
0923
0924 sentbuf[bn][++i] = SPACE;
0925 sentbuf[bn][++i] = '\0';
0926
0927 sentbufend[bn] = &sentbuf[bn][i];
0928 return numsentences[bn];
0929 }
0930
0931 static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
0932 {
0933 u_long start = vc->vc_origin, end;
0934
0935 if (from > 0)
0936 start += from * vc->vc_size_row;
0937 if (to > vc->vc_rows)
0938 to = vc->vc_rows;
0939 end = vc->vc_origin + (to * vc->vc_size_row);
0940 for (from = start; from < end; from = to) {
0941 to = from + vc->vc_size_row;
0942 say_from_to(vc, from, to, 1);
0943 }
0944 }
0945
0946 static void say_screen(struct vc_data *vc)
0947 {
0948 say_screen_from_to(vc, 0, vc->vc_rows);
0949 }
0950
0951 static void speakup_win_say(struct vc_data *vc)
0952 {
0953 u_long start, end, from, to;
0954
0955 if (win_start < 2) {
0956 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
0957 return;
0958 }
0959 start = vc->vc_origin + (win_top * vc->vc_size_row);
0960 end = vc->vc_origin + (win_bottom * vc->vc_size_row);
0961 while (start <= end) {
0962 from = start + (win_left * 2);
0963 to = start + (win_right * 2);
0964 say_from_to(vc, from, to, 1);
0965 start += vc->vc_size_row;
0966 }
0967 }
0968
0969 static void top_edge(struct vc_data *vc)
0970 {
0971 spk_parked |= 0x01;
0972 spk_pos = vc->vc_origin + 2 * spk_x;
0973 spk_y = 0;
0974 say_line(vc);
0975 }
0976
0977 static void bottom_edge(struct vc_data *vc)
0978 {
0979 spk_parked |= 0x01;
0980 spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
0981 spk_y = vc->vc_rows - 1;
0982 say_line(vc);
0983 }
0984
0985 static void left_edge(struct vc_data *vc)
0986 {
0987 spk_parked |= 0x01;
0988 spk_pos -= spk_x * 2;
0989 spk_x = 0;
0990 say_char(vc);
0991 }
0992
0993 static void right_edge(struct vc_data *vc)
0994 {
0995 spk_parked |= 0x01;
0996 spk_pos += (vc->vc_cols - spk_x - 1) * 2;
0997 spk_x = vc->vc_cols - 1;
0998 say_char(vc);
0999 }
1000
1001 static void say_first_char(struct vc_data *vc)
1002 {
1003 int i, len = get_line(vc);
1004 u16 ch;
1005
1006 spk_parked |= 0x01;
1007 if (len == 0) {
1008 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1009 return;
1010 }
1011 for (i = 0; i < len; i++)
1012 if (buf[i] != SPACE)
1013 break;
1014 ch = buf[i];
1015 spk_pos -= (spk_x - i) * 2;
1016 spk_x = i;
1017 synth_printf("%d, ", ++i);
1018 speak_char(ch);
1019 }
1020
1021 static void say_last_char(struct vc_data *vc)
1022 {
1023 int len = get_line(vc);
1024 u16 ch;
1025
1026 spk_parked |= 0x01;
1027 if (len == 0) {
1028 synth_printf("%s\n", spk_msg_get(MSG_BLANK));
1029 return;
1030 }
1031 ch = buf[--len];
1032 spk_pos -= (spk_x - len) * 2;
1033 spk_x = len;
1034 synth_printf("%d, ", ++len);
1035 speak_char(ch);
1036 }
1037
1038 static void say_position(struct vc_data *vc)
1039 {
1040 synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
1041 vc->vc_num + 1);
1042 synth_printf("\n");
1043 }
1044
1045
1046 static void say_char_num(struct vc_data *vc)
1047 {
1048 u_char tmp;
1049 u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
1050
1051 synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
1052 }
1053
1054
1055
1056 static void say_from_top(struct vc_data *vc)
1057 {
1058 say_screen_from_to(vc, 0, spk_y);
1059 }
1060
1061 static void say_to_bottom(struct vc_data *vc)
1062 {
1063 say_screen_from_to(vc, spk_y, vc->vc_rows);
1064 }
1065
1066 static void say_from_left(struct vc_data *vc)
1067 {
1068 say_line_from_to(vc, 0, spk_x, 1);
1069 }
1070
1071 static void say_to_right(struct vc_data *vc)
1072 {
1073 say_line_from_to(vc, spk_x, vc->vc_cols, 1);
1074 }
1075
1076
1077
1078 static void spkup_write(const u16 *in_buf, int count)
1079 {
1080 static int rep_count;
1081 static u16 ch = '\0', old_ch = '\0';
1082 static u_short char_type, last_type;
1083 int in_count = count;
1084
1085 spk_keydown = 0;
1086 while (count--) {
1087 if (cursor_track == read_all_mode) {
1088
1089 if ((in_buf == sentmarks[bn][currsentence]) &&
1090 (currsentence <= numsentences[bn]))
1091 synth_insert_next_index(currsentence++);
1092 }
1093 ch = *in_buf++;
1094 if (ch < 0x100)
1095 char_type = spk_chartab[ch];
1096 else
1097 char_type = ALPHA;
1098 if (ch == old_ch && !(char_type & B_NUM)) {
1099 if (++rep_count > 2)
1100 continue;
1101 } else {
1102 if ((last_type & CH_RPT) && rep_count > 2) {
1103 synth_printf(" ");
1104 synth_printf(spk_msg_get(MSG_REPEAT_DESC),
1105 ++rep_count);
1106 synth_printf(" ");
1107 }
1108 rep_count = 0;
1109 }
1110 if (ch == spk_lastkey) {
1111 rep_count = 0;
1112 if (spk_key_echo == 1 && ch >= MINECHOCHAR)
1113 speak_char(ch);
1114 } else if (char_type & B_ALPHA) {
1115 if ((synth_flags & SF_DEC) && (last_type & PUNC))
1116 synth_buffer_add(SPACE);
1117 synth_putwc_s(ch);
1118 } else if (char_type & B_NUM) {
1119 rep_count = 0;
1120 synth_putwc_s(ch);
1121 } else if (char_type & spk_punc_mask) {
1122 speak_char(ch);
1123 char_type &= ~PUNC;
1124 } else if (char_type & SYNTH_OK) {
1125
1126
1127
1128
1129
1130
1131
1132 if (ch != old_ch)
1133 synth_putwc_s(ch);
1134 else
1135 rep_count = 0;
1136 } else {
1137
1138 if (old_ch != ch)
1139 synth_buffer_add(SPACE);
1140 else
1141 rep_count = 0;
1142 }
1143 old_ch = ch;
1144 last_type = char_type;
1145 }
1146 spk_lastkey = 0;
1147 if (in_count > 2 && rep_count > 2) {
1148 if (last_type & CH_RPT) {
1149 synth_printf(" ");
1150 synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
1151 ++rep_count);
1152 synth_printf(" ");
1153 }
1154 rep_count = 0;
1155 }
1156 }
1157
1158 static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
1159
1160 static void read_all_doc(struct vc_data *vc);
1161 static void cursor_done(struct timer_list *unused);
1162 static DEFINE_TIMER(cursor_timer, cursor_done);
1163
1164 static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
1165 {
1166 unsigned long flags;
1167
1168 if (!synth || up_flag || spk_killed)
1169 return;
1170 spin_lock_irqsave(&speakup_info.spinlock, flags);
1171 if (cursor_track == read_all_mode) {
1172 switch (value) {
1173 case KVAL(K_SHIFT):
1174 del_timer(&cursor_timer);
1175 spk_shut_up &= 0xfe;
1176 spk_do_flush();
1177 read_all_doc(vc);
1178 break;
1179 case KVAL(K_CTRL):
1180 del_timer(&cursor_timer);
1181 cursor_track = prev_cursor_track;
1182 spk_shut_up &= 0xfe;
1183 spk_do_flush();
1184 break;
1185 }
1186 } else {
1187 spk_shut_up &= 0xfe;
1188 spk_do_flush();
1189 }
1190 if (spk_say_ctrl && value < NUM_CTL_LABELS)
1191 synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
1192 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1193 }
1194
1195 static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
1196 {
1197 unsigned long flags;
1198
1199 spin_lock_irqsave(&speakup_info.spinlock, flags);
1200 if (up_flag) {
1201 spk_lastkey = 0;
1202 spk_keydown = 0;
1203 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1204 return;
1205 }
1206 if (!synth || spk_killed) {
1207 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1208 return;
1209 }
1210 spk_shut_up &= 0xfe;
1211 spk_lastkey = value;
1212 spk_keydown++;
1213 spk_parked &= 0xfe;
1214 if (spk_key_echo == 2 && value >= MINECHOCHAR)
1215 speak_char(value);
1216 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1217 }
1218
1219 int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
1220 {
1221 int i = 0, states, key_data_len;
1222 const u_char *cp = key_info;
1223 u_char *cp1 = k_buffer;
1224 u_char ch, version, num_keys;
1225
1226 version = *cp++;
1227 if (version != KEY_MAP_VER) {
1228 pr_debug("version found %d should be %d\n",
1229 version, KEY_MAP_VER);
1230 return -EINVAL;
1231 }
1232 num_keys = *cp;
1233 states = (int)cp[1];
1234 key_data_len = (states + 1) * (num_keys + 1);
1235 if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
1236 pr_debug("too many key_infos (%d over %u)\n",
1237 key_data_len + SHIFT_TBL_SIZE + 4,
1238 (unsigned int)(sizeof(spk_key_buf)));
1239 return -EINVAL;
1240 }
1241 memset(k_buffer, 0, SHIFT_TBL_SIZE);
1242 memset(spk_our_keys, 0, sizeof(spk_our_keys));
1243 spk_shift_table = k_buffer;
1244 spk_our_keys[0] = spk_shift_table;
1245 cp1 += SHIFT_TBL_SIZE;
1246 memcpy(cp1, cp, key_data_len + 3);
1247
1248 cp1 += 2;
1249 for (i = 1; i <= states; i++) {
1250 ch = *cp1++;
1251 if (ch >= SHIFT_TBL_SIZE) {
1252 pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
1253 ch, SHIFT_TBL_SIZE);
1254 return -EINVAL;
1255 }
1256 spk_shift_table[ch] = i;
1257 }
1258 keymap_flags = *cp1++;
1259 while ((ch = *cp1)) {
1260 if (ch >= MAX_KEY) {
1261 pr_debug("(%d), not valid key, (max_allowed = %d)\n",
1262 ch, MAX_KEY);
1263 return -EINVAL;
1264 }
1265 spk_our_keys[ch] = cp1;
1266 cp1 += states + 1;
1267 }
1268 return 0;
1269 }
1270
1271 static struct var_t spk_vars[] = {
1272
1273 {BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
1274 {SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
1275 {ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
1276 {BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
1277 {BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
1278 {PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1279 {READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
1280 {CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
1281 {SAY_CONTROL, TOGGLE_0},
1282 {SAY_WORD_CTL, TOGGLE_0},
1283 {NO_INTERRUPT, TOGGLE_0},
1284 {KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
1285 V_LAST_VAR
1286 };
1287
1288 static void toggle_cursoring(struct vc_data *vc)
1289 {
1290 if (cursor_track == read_all_mode)
1291 cursor_track = prev_cursor_track;
1292 if (++cursor_track >= CT_Max)
1293 cursor_track = 0;
1294 synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
1295 }
1296
1297 void spk_reset_default_chars(void)
1298 {
1299 int i;
1300
1301
1302 for (i = 0; i < 256; i++) {
1303 if (spk_characters[i] &&
1304 (spk_characters[i] != spk_default_chars[i]))
1305 kfree(spk_characters[i]);
1306 }
1307
1308 memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
1309 }
1310
1311 void spk_reset_default_chartab(void)
1312 {
1313 memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
1314 }
1315
1316 static const struct st_bits_data *pb_edit;
1317
1318 static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
1319 {
1320 short mask = pb_edit->mask, ch_type = spk_chartab[ch];
1321
1322 if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
1323 return -1;
1324 if (ch == SPACE) {
1325 synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
1326 spk_special_handler = NULL;
1327 return 1;
1328 }
1329 if (mask < PUNC && !(ch_type & PUNC))
1330 return -1;
1331 spk_chartab[ch] ^= mask;
1332 speak_char(ch);
1333 synth_printf(" %s\n",
1334 (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
1335 spk_msg_get(MSG_OFF));
1336 return 1;
1337 }
1338
1339
1340 static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
1341 {
1342 int vc_num;
1343
1344 vc_num = vc->vc_num;
1345 if (!speakup_console[vc_num]) {
1346 speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
1347 gfp_flags);
1348 if (!speakup_console[vc_num])
1349 return -ENOMEM;
1350 speakup_date(vc);
1351 } else if (!spk_parked) {
1352 speakup_date(vc);
1353 }
1354
1355 return 0;
1356 }
1357
1358 static void speakup_deallocate(struct vc_data *vc)
1359 {
1360 int vc_num;
1361
1362 vc_num = vc->vc_num;
1363 kfree(speakup_console[vc_num]);
1364 speakup_console[vc_num] = NULL;
1365 }
1366
1367 enum read_all_command {
1368 RA_NEXT_SENT = KVAL(K_DOWN)+1,
1369 RA_PREV_LINE = KVAL(K_LEFT)+1,
1370 RA_NEXT_LINE = KVAL(K_RIGHT)+1,
1371 RA_PREV_SENT = KVAL(K_UP)+1,
1372 RA_DOWN_ARROW,
1373 RA_TIMER,
1374 RA_FIND_NEXT_SENT,
1375 RA_FIND_PREV_SENT,
1376 };
1377
1378 static u_char is_cursor;
1379 static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
1380 static int cursor_con;
1381
1382 static void reset_highlight_buffers(struct vc_data *);
1383
1384 static enum read_all_command read_all_key;
1385
1386 static int in_keyboard_notifier;
1387
1388 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command);
1389
1390 static void kbd_fakekey2(struct vc_data *vc, enum read_all_command command)
1391 {
1392 del_timer(&cursor_timer);
1393 speakup_fake_down_arrow();
1394 start_read_all_timer(vc, command);
1395 }
1396
1397 static void read_all_doc(struct vc_data *vc)
1398 {
1399 if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
1400 return;
1401 if (!synth_supports_indexing())
1402 return;
1403 if (cursor_track != read_all_mode)
1404 prev_cursor_track = cursor_track;
1405 cursor_track = read_all_mode;
1406 spk_reset_index_count(0);
1407 if (get_sentence_buf(vc, 0) == -1) {
1408 del_timer(&cursor_timer);
1409 if (!in_keyboard_notifier)
1410 speakup_fake_down_arrow();
1411 start_read_all_timer(vc, RA_DOWN_ARROW);
1412 } else {
1413 say_sentence_num(0, 0);
1414 synth_insert_next_index(0);
1415 start_read_all_timer(vc, RA_TIMER);
1416 }
1417 }
1418
1419 static void stop_read_all(struct vc_data *vc)
1420 {
1421 del_timer(&cursor_timer);
1422 cursor_track = prev_cursor_track;
1423 spk_shut_up &= 0xfe;
1424 spk_do_flush();
1425 }
1426
1427 static void start_read_all_timer(struct vc_data *vc, enum read_all_command command)
1428 {
1429 struct var_t *cursor_timeout;
1430
1431 cursor_con = vc->vc_num;
1432 read_all_key = command;
1433 cursor_timeout = spk_get_var(CURSOR_TIME);
1434 mod_timer(&cursor_timer,
1435 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1436 }
1437
1438 static void handle_cursor_read_all(struct vc_data *vc, enum read_all_command command)
1439 {
1440 int indcount, sentcount, rv, sn;
1441
1442 switch (command) {
1443 case RA_NEXT_SENT:
1444
1445 spk_get_index_count(&indcount, &sentcount);
1446
1447 spk_reset_index_count(sentcount + 1);
1448 if (indcount == 1) {
1449 if (!say_sentence_num(sentcount + 1, 0)) {
1450 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1451 return;
1452 }
1453 synth_insert_next_index(0);
1454 } else {
1455 sn = 0;
1456 if (!say_sentence_num(sentcount + 1, 1)) {
1457 sn = 1;
1458 spk_reset_index_count(sn);
1459 } else {
1460 synth_insert_next_index(0);
1461 }
1462 if (!say_sentence_num(sn, 0)) {
1463 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1464 return;
1465 }
1466 synth_insert_next_index(0);
1467 }
1468 start_read_all_timer(vc, RA_TIMER);
1469 break;
1470 case RA_PREV_SENT:
1471 break;
1472 case RA_NEXT_LINE:
1473 read_all_doc(vc);
1474 break;
1475 case RA_PREV_LINE:
1476 break;
1477 case RA_DOWN_ARROW:
1478 if (get_sentence_buf(vc, 0) == -1) {
1479 kbd_fakekey2(vc, RA_DOWN_ARROW);
1480 } else {
1481 say_sentence_num(0, 0);
1482 synth_insert_next_index(0);
1483 start_read_all_timer(vc, RA_TIMER);
1484 }
1485 break;
1486 case RA_FIND_NEXT_SENT:
1487 rv = get_sentence_buf(vc, 0);
1488 if (rv == -1)
1489 read_all_doc(vc);
1490 if (rv == 0) {
1491 kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
1492 } else {
1493 say_sentence_num(1, 0);
1494 synth_insert_next_index(0);
1495 start_read_all_timer(vc, RA_TIMER);
1496 }
1497 break;
1498 case RA_FIND_PREV_SENT:
1499 break;
1500 case RA_TIMER:
1501 spk_get_index_count(&indcount, &sentcount);
1502 if (indcount < 2)
1503 kbd_fakekey2(vc, RA_DOWN_ARROW);
1504 else
1505 start_read_all_timer(vc, RA_TIMER);
1506 break;
1507 }
1508 }
1509
1510 static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1511 {
1512 unsigned long flags;
1513
1514 spin_lock_irqsave(&speakup_info.spinlock, flags);
1515 if (cursor_track == read_all_mode) {
1516 spk_parked &= 0xfe;
1517 if (!synth || up_flag || spk_shut_up) {
1518 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1519 return NOTIFY_STOP;
1520 }
1521 del_timer(&cursor_timer);
1522 spk_shut_up &= 0xfe;
1523 spk_do_flush();
1524 start_read_all_timer(vc, value + 1);
1525 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1526 return NOTIFY_STOP;
1527 }
1528 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1529 return NOTIFY_OK;
1530 }
1531
1532 static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
1533 {
1534 unsigned long flags;
1535 struct var_t *cursor_timeout;
1536
1537 spin_lock_irqsave(&speakup_info.spinlock, flags);
1538 spk_parked &= 0xfe;
1539 if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
1540 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1541 return;
1542 }
1543 spk_shut_up &= 0xfe;
1544 if (spk_no_intr)
1545 spk_do_flush();
1546
1547
1548
1549 is_cursor = value + 1;
1550 old_cursor_pos = vc->vc_pos;
1551 old_cursor_x = vc->state.x;
1552 old_cursor_y = vc->state.y;
1553 speakup_console[vc->vc_num]->ht.cy = vc->state.y;
1554 cursor_con = vc->vc_num;
1555 if (cursor_track == CT_Highlight)
1556 reset_highlight_buffers(vc);
1557 cursor_timeout = spk_get_var(CURSOR_TIME);
1558 mod_timer(&cursor_timer,
1559 jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
1560 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1561 }
1562
1563 static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
1564 {
1565 int i, bi, hi;
1566 int vc_num = vc->vc_num;
1567
1568 bi = (vc->vc_attr & 0x70) >> 4;
1569 hi = speakup_console[vc_num]->ht.highsize[bi];
1570
1571 i = 0;
1572 if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
1573 speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
1574 speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
1575 speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
1576 }
1577 while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
1578 if (ic[i] > 32) {
1579 speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
1580 hi++;
1581 } else if ((ic[i] == 32) && (hi != 0)) {
1582 if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
1583 32) {
1584 speakup_console[vc_num]->ht.highbuf[bi][hi] =
1585 ic[i];
1586 hi++;
1587 }
1588 }
1589 i++;
1590 }
1591 speakup_console[vc_num]->ht.highsize[bi] = hi;
1592 }
1593
1594 static void reset_highlight_buffers(struct vc_data *vc)
1595 {
1596 int i;
1597 int vc_num = vc->vc_num;
1598
1599 for (i = 0; i < 8; i++)
1600 speakup_console[vc_num]->ht.highsize[i] = 0;
1601 }
1602
1603 static int count_highlight_color(struct vc_data *vc)
1604 {
1605 int i, bg;
1606 int cc;
1607 int vc_num = vc->vc_num;
1608 u16 ch;
1609 u16 *start = (u16 *)vc->vc_origin;
1610
1611 for (i = 0; i < 8; i++)
1612 speakup_console[vc_num]->ht.bgcount[i] = 0;
1613
1614 for (i = 0; i < vc->vc_rows; i++) {
1615 u16 *end = start + vc->vc_cols * 2;
1616 u16 *ptr;
1617
1618 for (ptr = start; ptr < end; ptr++) {
1619 ch = get_attributes(vc, ptr);
1620 bg = (ch & 0x70) >> 4;
1621 speakup_console[vc_num]->ht.bgcount[bg]++;
1622 }
1623 start += vc->vc_size_row;
1624 }
1625
1626 cc = 0;
1627 for (i = 0; i < 8; i++)
1628 if (speakup_console[vc_num]->ht.bgcount[i] > 0)
1629 cc++;
1630 return cc;
1631 }
1632
1633 static int get_highlight_color(struct vc_data *vc)
1634 {
1635 int i, j;
1636 unsigned int cptr[8];
1637 int vc_num = vc->vc_num;
1638
1639 for (i = 0; i < 8; i++)
1640 cptr[i] = i;
1641
1642 for (i = 0; i < 7; i++)
1643 for (j = i + 1; j < 8; j++)
1644 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
1645 speakup_console[vc_num]->ht.bgcount[cptr[j]])
1646 swap(cptr[i], cptr[j]);
1647
1648 for (i = 0; i < 8; i++)
1649 if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
1650 if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
1651 return cptr[i];
1652 return -1;
1653 }
1654
1655 static int speak_highlight(struct vc_data *vc)
1656 {
1657 int hc, d;
1658 int vc_num = vc->vc_num;
1659
1660 if (count_highlight_color(vc) == 1)
1661 return 0;
1662 hc = get_highlight_color(vc);
1663 if (hc != -1) {
1664 d = vc->state.y - speakup_console[vc_num]->ht.cy;
1665 if ((d == 1) || (d == -1))
1666 if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
1667 return 0;
1668 spk_parked |= 0x01;
1669 spk_do_flush();
1670 spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
1671 speakup_console[vc_num]->ht.highsize[hc]);
1672 spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
1673 spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
1674 spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
1675 return 1;
1676 }
1677 return 0;
1678 }
1679
1680 static void cursor_done(struct timer_list *unused)
1681 {
1682 struct vc_data *vc = vc_cons[cursor_con].d;
1683 unsigned long flags;
1684
1685 del_timer(&cursor_timer);
1686 spin_lock_irqsave(&speakup_info.spinlock, flags);
1687 if (cursor_con != fg_console) {
1688 is_cursor = 0;
1689 goto out;
1690 }
1691 speakup_date(vc);
1692 if (win_enabled) {
1693 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1694 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1695 spk_keydown = 0;
1696 is_cursor = 0;
1697 goto out;
1698 }
1699 }
1700 if (cursor_track == read_all_mode) {
1701 handle_cursor_read_all(vc, read_all_key);
1702 goto out;
1703 }
1704 if (cursor_track == CT_Highlight) {
1705 if (speak_highlight(vc)) {
1706 spk_keydown = 0;
1707 is_cursor = 0;
1708 goto out;
1709 }
1710 }
1711 if (cursor_track == CT_Window)
1712 speakup_win_say(vc);
1713 else if (is_cursor == 1 || is_cursor == 4)
1714 say_line_from_to(vc, 0, vc->vc_cols, 0);
1715 else
1716 say_char(vc);
1717 spk_keydown = 0;
1718 is_cursor = 0;
1719 out:
1720 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1721 }
1722
1723
1724 static void speakup_bs(struct vc_data *vc)
1725 {
1726 unsigned long flags;
1727
1728 if (!speakup_console[vc->vc_num])
1729 return;
1730 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1731
1732 return;
1733 if (!spk_parked)
1734 speakup_date(vc);
1735 if (spk_shut_up || !synth) {
1736 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1737 return;
1738 }
1739 if (vc->vc_num == fg_console && spk_keydown) {
1740 spk_keydown = 0;
1741 if (!is_cursor)
1742 say_char(vc);
1743 }
1744 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1745 }
1746
1747
1748 static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
1749 {
1750 unsigned long flags;
1751
1752 if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
1753 return;
1754 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1755
1756 return;
1757 if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
1758 bleep(3);
1759 if ((is_cursor) || (cursor_track == read_all_mode)) {
1760 if (cursor_track == CT_Highlight)
1761 update_color_buffer(vc, str, len);
1762 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1763 return;
1764 }
1765 if (win_enabled) {
1766 if (vc->state.x >= win_left && vc->state.x <= win_right &&
1767 vc->state.y >= win_top && vc->state.y <= win_bottom) {
1768 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1769 return;
1770 }
1771 }
1772
1773 spkup_write(str, len);
1774 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1775 }
1776
1777 static void speakup_con_update(struct vc_data *vc)
1778 {
1779 unsigned long flags;
1780
1781 if (!speakup_console[vc->vc_num] || spk_parked)
1782 return;
1783 if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
1784
1785 return;
1786 speakup_date(vc);
1787 if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
1788 synth_printf("%s", spk_str_pause);
1789 spk_paused = true;
1790 }
1791 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1792 }
1793
1794 static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
1795 {
1796 unsigned long flags;
1797 int on_off = 2;
1798 char *label;
1799
1800 if (!synth || up_flag || spk_killed)
1801 return;
1802 spin_lock_irqsave(&speakup_info.spinlock, flags);
1803 spk_shut_up &= 0xfe;
1804 if (spk_no_intr)
1805 spk_do_flush();
1806 switch (value) {
1807 case KVAL(K_CAPS):
1808 label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
1809 on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
1810 break;
1811 case KVAL(K_NUM):
1812 label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
1813 on_off = vt_get_leds(fg_console, VC_NUMLOCK);
1814 break;
1815 case KVAL(K_HOLD):
1816 label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
1817 on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
1818 if (speakup_console[vc->vc_num])
1819 speakup_console[vc->vc_num]->tty_stopped = on_off;
1820 break;
1821 default:
1822 spk_parked &= 0xfe;
1823 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1824 return;
1825 }
1826 if (on_off < 2)
1827 synth_printf("%s %s\n",
1828 label, spk_msg_get(MSG_STATUS_START + on_off));
1829 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
1830 }
1831
1832 static int inc_dec_var(u_char value)
1833 {
1834 struct st_var_header *p_header;
1835 struct var_t *var_data;
1836 char num_buf[32];
1837 char *cp = num_buf;
1838 char *pn;
1839 int var_id = (int)value - VAR_START;
1840 int how = (var_id & 1) ? E_INC : E_DEC;
1841
1842 var_id = var_id / 2 + FIRST_SET_VAR;
1843 p_header = spk_get_var_header(var_id);
1844 if (!p_header)
1845 return -1;
1846 if (p_header->var_type != VAR_NUM)
1847 return -1;
1848 var_data = p_header->data;
1849 if (spk_set_num_var(1, p_header, how) != 0)
1850 return -1;
1851 if (!spk_close_press) {
1852 for (pn = p_header->name; *pn; pn++) {
1853 if (*pn == '_')
1854 *cp = SPACE;
1855 else
1856 *cp++ = *pn;
1857 }
1858 }
1859 snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
1860 var_data->u.n.value);
1861 synth_printf("%s", num_buf);
1862 return 0;
1863 }
1864
1865 static void speakup_win_set(struct vc_data *vc)
1866 {
1867 char info[40];
1868
1869 if (win_start > 1) {
1870 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
1871 return;
1872 }
1873 if (spk_x < win_left || spk_y < win_top) {
1874 synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
1875 return;
1876 }
1877 if (win_start && spk_x == win_left && spk_y == win_top) {
1878 win_left = 0;
1879 win_right = vc->vc_cols - 1;
1880 win_bottom = spk_y;
1881 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
1882 (int)win_top + 1);
1883 } else {
1884 if (!win_start) {
1885 win_top = spk_y;
1886 win_left = spk_x;
1887 } else {
1888 win_bottom = spk_y;
1889 win_right = spk_x;
1890 }
1891 snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
1892 (win_start) ?
1893 spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
1894 (int)spk_y + 1, (int)spk_x + 1);
1895 }
1896 synth_printf("%s\n", info);
1897 win_start++;
1898 }
1899
1900 static void speakup_win_clear(struct vc_data *vc)
1901 {
1902 win_top = 0;
1903 win_bottom = 0;
1904 win_left = 0;
1905 win_right = 0;
1906 win_start = 0;
1907 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
1908 }
1909
1910 static void speakup_win_enable(struct vc_data *vc)
1911 {
1912 if (win_start < 2) {
1913 synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
1914 return;
1915 }
1916 win_enabled ^= 1;
1917 if (win_enabled)
1918 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
1919 else
1920 synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
1921 }
1922
1923 static void speakup_bits(struct vc_data *vc)
1924 {
1925 int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
1926
1927 if (spk_special_handler || val < 1 || val > 6) {
1928 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
1929 return;
1930 }
1931 pb_edit = &spk_punc_info[val];
1932 synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
1933 spk_special_handler = edit_bits;
1934 }
1935
1936 static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
1937 {
1938 static u_char goto_buf[8];
1939 static int num;
1940 int maxlen;
1941 char *cp;
1942 u16 wch;
1943
1944 if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
1945 goto do_goto;
1946 if (type == KT_LATIN && ch == '\n')
1947 goto do_goto;
1948 if (type != 0)
1949 goto oops;
1950 if (ch == 8) {
1951 u16 wch;
1952
1953 if (num == 0)
1954 return -1;
1955 wch = goto_buf[--num];
1956 goto_buf[num] = '\0';
1957 spkup_write(&wch, 1);
1958 return 1;
1959 }
1960 if (ch < '+' || ch > 'y')
1961 goto oops;
1962 wch = ch;
1963 goto_buf[num++] = ch;
1964 goto_buf[num] = '\0';
1965 spkup_write(&wch, 1);
1966 maxlen = (*goto_buf >= '0') ? 3 : 4;
1967 if ((ch == '+' || ch == '-') && num == 1)
1968 return 1;
1969 if (ch >= '0' && ch <= '9' && num < maxlen)
1970 return 1;
1971 if (num < maxlen - 1 || num > maxlen)
1972 goto oops;
1973 if (ch < 'x' || ch > 'y') {
1974 oops:
1975 if (!spk_killed)
1976 synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
1977 goto_buf[num = 0] = '\0';
1978 spk_special_handler = NULL;
1979 return 1;
1980 }
1981
1982
1983 goto_pos = simple_strtoul(goto_buf, &cp, 10);
1984
1985 if (*cp == 'x') {
1986 if (*goto_buf < '0')
1987 goto_pos += spk_x;
1988 else if (goto_pos > 0)
1989 goto_pos--;
1990
1991 if (goto_pos >= vc->vc_cols)
1992 goto_pos = vc->vc_cols - 1;
1993 goto_x = 1;
1994 } else {
1995 if (*goto_buf < '0')
1996 goto_pos += spk_y;
1997 else if (goto_pos > 0)
1998 goto_pos--;
1999
2000 if (goto_pos >= vc->vc_rows)
2001 goto_pos = vc->vc_rows - 1;
2002 goto_x = 0;
2003 }
2004 goto_buf[num = 0] = '\0';
2005 do_goto:
2006 spk_special_handler = NULL;
2007 spk_parked |= 0x01;
2008 if (goto_x) {
2009 spk_pos -= spk_x * 2;
2010 spk_x = goto_pos;
2011 spk_pos += goto_pos * 2;
2012 say_word(vc);
2013 } else {
2014 spk_y = goto_pos;
2015 spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
2016 say_line(vc);
2017 }
2018 return 1;
2019 }
2020
2021 static void speakup_goto(struct vc_data *vc)
2022 {
2023 if (spk_special_handler) {
2024 synth_printf("%s\n", spk_msg_get(MSG_ERROR));
2025 return;
2026 }
2027 synth_printf("%s\n", spk_msg_get(MSG_GOTO));
2028 spk_special_handler = handle_goto;
2029 }
2030
2031 static void speakup_help(struct vc_data *vc)
2032 {
2033 spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
2034 }
2035
2036 static void do_nothing(struct vc_data *vc)
2037 {
2038 return;
2039 }
2040
2041 static u_char key_speakup, spk_key_locked;
2042
2043 static void speakup_lock(struct vc_data *vc)
2044 {
2045 if (!spk_key_locked) {
2046 spk_key_locked = 16;
2047 key_speakup = 16;
2048 } else {
2049 spk_key_locked = 0;
2050 key_speakup = 0;
2051 }
2052 }
2053
2054 typedef void (*spkup_hand) (struct vc_data *);
2055 static spkup_hand spkup_handler[] = {
2056
2057 do_nothing, speakup_goto, speech_kill, speakup_shut_up,
2058 speakup_cut, speakup_paste, say_first_char, say_last_char,
2059 say_char, say_prev_char, say_next_char,
2060 say_word, say_prev_word, say_next_word,
2061 say_line, say_prev_line, say_next_line,
2062 top_edge, bottom_edge, left_edge, right_edge,
2063 spell_word, spell_word, say_screen,
2064 say_position, say_attributes,
2065 speakup_off, speakup_parked, say_line,
2066 say_from_top, say_to_bottom,
2067 say_from_left, say_to_right,
2068 say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
2069 speakup_bits, speakup_bits, speakup_bits,
2070 speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
2071 speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
2072 };
2073
2074 static void do_spkup(struct vc_data *vc, u_char value)
2075 {
2076 if (spk_killed && value != SPEECH_KILL)
2077 return;
2078 spk_keydown = 0;
2079 spk_lastkey = 0;
2080 spk_shut_up &= 0xfe;
2081 this_speakup_key = value;
2082 if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
2083 spk_do_flush();
2084 (*spkup_handler[value]) (vc);
2085 } else {
2086 if (inc_dec_var(value) < 0)
2087 bleep(9);
2088 }
2089 }
2090
2091 static const char *pad_chars = "0123456789+-*/\015,.?()";
2092
2093 static int
2094 speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
2095 int up_flag)
2096 {
2097 unsigned long flags;
2098 int kh;
2099 u_char *key_info;
2100 u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
2101 u_char shift_info, offset;
2102 int ret = 0;
2103
2104 if (!synth)
2105 return 0;
2106
2107 spin_lock_irqsave(&speakup_info.spinlock, flags);
2108 tty = vc->port.tty;
2109 if (type >= 0xf0)
2110 type -= 0xf0;
2111 if (type == KT_PAD &&
2112 (vt_get_leds(fg_console, VC_NUMLOCK))) {
2113 if (up_flag) {
2114 spk_keydown = 0;
2115 goto out;
2116 }
2117 value = pad_chars[value];
2118 spk_lastkey = value;
2119 spk_keydown++;
2120 spk_parked &= 0xfe;
2121 goto no_map;
2122 }
2123 if (keycode >= MAX_KEY)
2124 goto no_map;
2125 key_info = spk_our_keys[keycode];
2126 if (!key_info)
2127 goto no_map;
2128
2129 if ((cursor_track == read_all_mode) && (!up_flag)) {
2130 switch (value) {
2131 case KVAL(K_DOWN):
2132 case KVAL(K_UP):
2133 case KVAL(K_LEFT):
2134 case KVAL(K_RIGHT):
2135 case KVAL(K_PGUP):
2136 case KVAL(K_PGDN):
2137 break;
2138 default:
2139 stop_read_all(vc);
2140 break;
2141 }
2142 }
2143 shift_info = (shift_state & 0x0f) + key_speakup;
2144 offset = spk_shift_table[shift_info];
2145 if (offset) {
2146 new_key = key_info[offset];
2147 if (new_key) {
2148 ret = 1;
2149 if (new_key == SPK_KEY) {
2150 if (!spk_key_locked)
2151 key_speakup = (up_flag) ? 0 : 16;
2152 if (up_flag || spk_killed)
2153 goto out;
2154 spk_shut_up &= 0xfe;
2155 spk_do_flush();
2156 goto out;
2157 }
2158 if (up_flag)
2159 goto out;
2160 if (last_keycode == keycode &&
2161 time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
2162 spk_close_press = 1;
2163 offset = spk_shift_table[shift_info + 32];
2164
2165 if (offset && key_info[offset])
2166 new_key = key_info[offset];
2167 }
2168 last_keycode = keycode;
2169 last_spk_jiffy = jiffies;
2170 type = KT_SPKUP;
2171 value = new_key;
2172 }
2173 }
2174 no_map:
2175 if (type == KT_SPKUP && !spk_special_handler) {
2176 do_spkup(vc, new_key);
2177 spk_close_press = 0;
2178 ret = 1;
2179 goto out;
2180 }
2181 if (up_flag || spk_killed || type == KT_SHIFT)
2182 goto out;
2183 spk_shut_up &= 0xfe;
2184 kh = (value == KVAL(K_DOWN)) ||
2185 (value == KVAL(K_UP)) ||
2186 (value == KVAL(K_LEFT)) ||
2187 (value == KVAL(K_RIGHT));
2188 if ((cursor_track != read_all_mode) || !kh)
2189 if (!spk_no_intr)
2190 spk_do_flush();
2191 if (spk_special_handler) {
2192 if (type == KT_SPEC && value == 1) {
2193 value = '\n';
2194 type = KT_LATIN;
2195 } else if (type == KT_LETTER) {
2196 type = KT_LATIN;
2197 } else if (value == 0x7f) {
2198 value = 8;
2199 }
2200 ret = (*spk_special_handler) (vc, type, value, keycode);
2201 spk_close_press = 0;
2202 if (ret < 0)
2203 bleep(9);
2204 goto out;
2205 }
2206 last_keycode = 0;
2207 out:
2208 spin_unlock_irqrestore(&speakup_info.spinlock, flags);
2209 return ret;
2210 }
2211
2212 static int keyboard_notifier_call(struct notifier_block *nb,
2213 unsigned long code, void *_param)
2214 {
2215 struct keyboard_notifier_param *param = _param;
2216 struct vc_data *vc = param->vc;
2217 int up = !param->down;
2218 int ret = NOTIFY_OK;
2219 static int keycode;
2220
2221 in_keyboard_notifier = 1;
2222
2223 if (vc->vc_mode == KD_GRAPHICS)
2224 goto out;
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235 if (speakup_fake_key_pressed())
2236 goto out;
2237
2238 switch (code) {
2239 case KBD_KEYCODE:
2240
2241 keycode = param->value;
2242 break;
2243 case KBD_UNBOUND_KEYCODE:
2244
2245 break;
2246 case KBD_UNICODE:
2247
2248 break;
2249 case KBD_KEYSYM:
2250 if (speakup_key(vc, param->shift, keycode, param->value, up))
2251 ret = NOTIFY_STOP;
2252 else if (KTYP(param->value) == KT_CUR)
2253 ret = pre_handle_cursor(vc, KVAL(param->value), up);
2254 break;
2255 case KBD_POST_KEYSYM:{
2256 unsigned char type = KTYP(param->value) - 0xf0;
2257 unsigned char val = KVAL(param->value);
2258
2259 switch (type) {
2260 case KT_SHIFT:
2261 do_handle_shift(vc, val, up);
2262 break;
2263 case KT_LATIN:
2264 case KT_LETTER:
2265 do_handle_latin(vc, val, up);
2266 break;
2267 case KT_CUR:
2268 do_handle_cursor(vc, val, up);
2269 break;
2270 case KT_SPEC:
2271 do_handle_spec(vc, val, up);
2272 break;
2273 }
2274 break;
2275 }
2276 }
2277 out:
2278 in_keyboard_notifier = 0;
2279 return ret;
2280 }
2281
2282 static int vt_notifier_call(struct notifier_block *nb,
2283 unsigned long code, void *_param)
2284 {
2285 struct vt_notifier_param *param = _param;
2286 struct vc_data *vc = param->vc;
2287
2288 switch (code) {
2289 case VT_ALLOCATE:
2290 if (vc->vc_mode == KD_TEXT)
2291 speakup_allocate(vc, GFP_ATOMIC);
2292 break;
2293 case VT_DEALLOCATE:
2294 speakup_deallocate(vc);
2295 break;
2296 case VT_WRITE:
2297 if (param->c == '\b') {
2298 speakup_bs(vc);
2299 } else {
2300 u16 d = param->c;
2301
2302 speakup_con_write(vc, &d, 1);
2303 }
2304 break;
2305 case VT_UPDATE:
2306 speakup_con_update(vc);
2307 break;
2308 }
2309 return NOTIFY_OK;
2310 }
2311
2312
2313 static void __exit speakup_exit(void)
2314 {
2315 int i;
2316
2317 unregister_keyboard_notifier(&keyboard_notifier_block);
2318 unregister_vt_notifier(&vt_notifier_block);
2319 speakup_unregister_devsynth();
2320 speakup_cancel_selection();
2321 speakup_cancel_paste();
2322 del_timer_sync(&cursor_timer);
2323 kthread_stop(speakup_task);
2324 speakup_task = NULL;
2325 mutex_lock(&spk_mutex);
2326 synth_release();
2327 mutex_unlock(&spk_mutex);
2328 spk_ttyio_unregister_ldisc();
2329
2330 speakup_kobj_exit();
2331
2332 for (i = 0; i < MAX_NR_CONSOLES; i++)
2333 kfree(speakup_console[i]);
2334
2335 speakup_remove_virtual_keyboard();
2336
2337 for (i = 0; i < MAXVARS; i++)
2338 speakup_unregister_var(i);
2339
2340 for (i = 0; i < 256; i++) {
2341 if (spk_characters[i] != spk_default_chars[i])
2342 kfree(spk_characters[i]);
2343 }
2344
2345 spk_free_user_msgs();
2346 }
2347
2348
2349 static int __init speakup_init(void)
2350 {
2351 int i;
2352 long err = 0;
2353 struct vc_data *vc = vc_cons[fg_console].d;
2354 struct var_t *var;
2355
2356
2357 spk_initialize_msgs();
2358 spk_reset_default_chars();
2359 spk_reset_default_chartab();
2360 spk_strlwr(synth_name);
2361 spk_vars[0].u.n.high = vc->vc_cols;
2362 for (var = spk_vars; var->var_id != MAXVARS; var++)
2363 speakup_register_var(var);
2364 for (var = synth_time_vars;
2365 (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
2366 speakup_register_var(var);
2367 for (i = 1; spk_punc_info[i].mask != 0; i++)
2368 spk_set_mask_bits(NULL, i, 2);
2369
2370 spk_set_key_info(spk_key_defaults, spk_key_buf);
2371
2372
2373 err = speakup_add_virtual_keyboard();
2374 if (err)
2375 goto error_virtkeyboard;
2376
2377 for (i = 0; i < MAX_NR_CONSOLES; i++)
2378 if (vc_cons[i].d) {
2379 err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
2380 if (err)
2381 goto error_kobjects;
2382 }
2383
2384 if (spk_quiet_boot)
2385 spk_shut_up |= 0x01;
2386
2387 err = speakup_kobj_init();
2388 if (err)
2389 goto error_kobjects;
2390
2391 spk_ttyio_register_ldisc();
2392 synth_init(synth_name);
2393 speakup_register_devsynth();
2394
2395
2396
2397
2398
2399
2400 err = register_keyboard_notifier(&keyboard_notifier_block);
2401 if (err)
2402 goto error_kbdnotifier;
2403 err = register_vt_notifier(&vt_notifier_block);
2404 if (err)
2405 goto error_vtnotifier;
2406
2407 speakup_task = kthread_create(speakup_thread, NULL, "speakup");
2408
2409 if (IS_ERR(speakup_task)) {
2410 err = PTR_ERR(speakup_task);
2411 goto error_task;
2412 }
2413
2414 set_user_nice(speakup_task, 10);
2415 wake_up_process(speakup_task);
2416
2417 pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
2418 pr_info("synth name on entry is: %s\n", synth_name);
2419 goto out;
2420
2421 error_task:
2422 unregister_vt_notifier(&vt_notifier_block);
2423
2424 error_vtnotifier:
2425 unregister_keyboard_notifier(&keyboard_notifier_block);
2426 del_timer(&cursor_timer);
2427
2428 error_kbdnotifier:
2429 speakup_unregister_devsynth();
2430 mutex_lock(&spk_mutex);
2431 synth_release();
2432 mutex_unlock(&spk_mutex);
2433 speakup_kobj_exit();
2434
2435 error_kobjects:
2436 for (i = 0; i < MAX_NR_CONSOLES; i++)
2437 kfree(speakup_console[i]);
2438
2439 speakup_remove_virtual_keyboard();
2440
2441 error_virtkeyboard:
2442 for (i = 0; i < MAXVARS; i++)
2443 speakup_unregister_var(i);
2444
2445 for (i = 0; i < 256; i++) {
2446 if (spk_characters[i] != spk_default_chars[i])
2447 kfree(spk_characters[i]);
2448 }
2449
2450 spk_free_user_msgs();
2451
2452 out:
2453 return err;
2454 }
2455
2456 module_init(speakup_init);
2457 module_exit(speakup_exit);