Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags   |
// SPDX-License-Identifier: GPL-2.0+
/* speakup.c
* review functions for the speakup screen review package.
* originally written by: Kirk Reiser and Andy Berdan.
*
* extensively modified by David Borowski.
*
** Copyright (C) 1998 Kirk Reiser.
* Copyright (C) 2003 David Borowski.
*/
#include <linux/kernel.h>
#include <linux/vt.h>
#include <linux/tty.h>
#include <linux/mm.h> /* __get_free_page() and friends */
#include <linux/vt_kern.h>
#include <linux/ctype.h>
#include <linux/selection.h>
#include <linux/unistd.h>
#include <linux/jiffies.h>
#include <linux/kthread.h>
#include <linux/keyboard.h> /* for KT_SHIFT */
#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
#include <linux/input.h>
#include <linux/kmod.h>
/* speakup_*_selection */
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/consolemap.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
#include <linux/uaccess.h> /* copy_from|to|user() and others */
#include "spk_priv.h"
#include "speakup.h"
#define MAX_DELAY msecs_to_jiffies(500)
#define MINECHOCHAR SPACE
MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
MODULE_AUTHOR("Daniel Drake <dsd@gentoo.org>");
MODULE_DESCRIPTION("Speakup console speech");
MODULE_LICENSE("GPL");
MODULE_VERSION(SPEAKUP_VERSION);
char *synth_name;
module_param_named(synth, synth_name, charp, 0444);
module_param_named(quiet, spk_quiet_boot, bool, 0444);
MODULE_PARM_DESC(synth, "Synth to start if speakup is built in.");
MODULE_PARM_DESC(quiet, "Do not announce when the synthesizer is found.");
special_func spk_special_handler;
short spk_pitch_shift, synth_flags;
static u16 buf[256];
int spk_attrib_bleep, spk_bleeps, spk_bleep_time = 10;
int spk_no_intr, spk_spell_delay;
int spk_key_echo, spk_say_word_ctl;
int spk_say_ctrl, spk_bell_pos;
short spk_punc_mask;
int spk_punc_level, spk_reading_punc;
char spk_str_caps_start[MAXVARLEN + 1] = "\0";
char spk_str_caps_stop[MAXVARLEN + 1] = "\0";
char spk_str_pause[MAXVARLEN + 1] = "\0";
bool spk_paused;
const struct st_bits_data spk_punc_info[] = {
<------>{"none", "", 0},
<------>{"some", "/$%&@", SOME},
<------>{"most", "$%&#()=+*/@^<>|\\", MOST},
<------>{"all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC},
<------>{"delimiters", "", B_WDLM},
<------>{"repeats", "()", CH_RPT},
<------>{"extended numeric", "", B_EXNUM},
<------>{"symbols", "", B_SYM},
<------>{NULL, NULL}
};
static char mark_cut_flag;
#define MAX_KEY 160
static u_char *spk_shift_table;
u_char *spk_our_keys[MAX_KEY];
u_char spk_key_buf[600];
const u_char spk_key_defaults[] = {
#include "speakupmap.h"
};
/* Speakup Cursor Track Variables */
static int cursor_track = 1, prev_cursor_track = 1;
/* cursor track modes, must be ordered same as cursor_msgs */
enum {
<------>CT_Off = 0,
<------>CT_On,
<------>CT_Highlight,
<------>CT_Window,
<------>CT_Max
};
#define read_all_mode CT_Max
static struct tty_struct *tty;
static void spkup_write(const u16 *in_buf, int count);
static char *phonetic[] = {
<------>"alfa", "bravo", "charlie", "delta", "echo", "foxtrot", "golf", "hotel",
<------>"india", "juliett", "keelo", "leema", "mike", "november", "oscar",
<------> "papa",
<------>"keh beck", "romeo", "sierra", "tango", "uniform", "victer", "whiskey",
<------>"x ray", "yankee", "zulu"
};
/* array of 256 char pointers (one for each character description)
* initialized to default_chars and user selectable via
* /proc/speakup/characters
*/
char *spk_characters[256];
char *spk_default_chars[256] = {
/*000*/ "null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
/*008*/ "^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
/*016*/ "^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
/*024*/ "^x", "^y", "^z", "control", "control", "control", "control",
<------> "control",
/*032*/ "space", "bang!", "quote", "number", "dollar", "percent", "and",
<------> "tick",
/*040*/ "left paren", "right paren", "star", "plus", "comma", "dash",
<------> "dot",
<------>"slash",
/*048*/ "zero", "one", "two", "three", "four", "five", "six", "seven",
<------>"eight", "nine",
/*058*/ "colon", "semmy", "less", "equals", "greater", "question", "at",
/*065*/ "EIGH", "B", "C", "D", "E", "F", "G",
/*072*/ "H", "I", "J", "K", "L", "M", "N", "O",
/*080*/ "P", "Q", "R", "S", "T", "U", "V", "W", "X",
/*089*/ "Y", "ZED", "left bracket", "backslash", "right bracket",
<------> "caret",
<------>"line",
/*096*/ "accent", "a", "b", "c", "d", "e", "f", "g",
/*104*/ "h", "i", "j", "k", "l", "m", "n", "o",
/*112*/ "p", "q", "r", "s", "t", "u", "v", "w",
/*120*/ "x", "y", "zed", "left brace", "bar", "right brace", "tihlduh",
/*127*/ "del", "control", "control", "control", "control", "control",
<------> "control", "control", "control", "control", "control",
/*138*/ "control", "control", "control", "control", "control",
<------> "control", "control", "control", "control", "control",
<------> "control", "control",
/*150*/ "control", "control", "control", "control", "control",
<------> "control", "control", "control", "control", "control",
/*160*/ "nbsp", "inverted bang",
/*162*/ "cents", "pounds", "currency", "yen", "broken bar", "section",
/*168*/ "diaeresis", "copyright", "female ordinal", "double left angle",
/*172*/ "not", "soft hyphen", "registered", "macron",
/*176*/ "degrees", "plus or minus", "super two", "super three",
/*180*/ "acute accent", "micro", "pilcrow", "middle dot",
/*184*/ "cedilla", "super one", "male ordinal", "double right angle",
/*188*/ "one quarter", "one half", "three quarters",
<------> "inverted question",
/*192*/ "A GRAVE", "A ACUTE", "A CIRCUMFLEX", "A TILDE", "A OOMLAUT",
<------> "A RING",
/*198*/ "AE", "C CIDELLA", "E GRAVE", "E ACUTE", "E CIRCUMFLEX",
<------> "E OOMLAUT",
/*204*/ "I GRAVE", "I ACUTE", "I CIRCUMFLEX", "I OOMLAUT", "ETH",
<------> "N TILDE",
/*210*/ "O GRAVE", "O ACUTE", "O CIRCUMFLEX", "O TILDE", "O OOMLAUT",
/*215*/ "multiplied by", "O STROKE", "U GRAVE", "U ACUTE",
<------> "U CIRCUMFLEX",
/*220*/ "U OOMLAUT", "Y ACUTE", "THORN", "sharp s", "a grave",
/*225*/ "a acute", "a circumflex", "a tilde", "a oomlaut", "a ring",
/*230*/ "ae", "c cidella", "e grave", "e acute",
/*234*/ "e circumflex", "e oomlaut", "i grave", "i acute",
<------> "i circumflex",
/*239*/ "i oomlaut", "eth", "n tilde", "o grave", "o acute",
<------> "o circumflex",
/*245*/ "o tilde", "o oomlaut", "divided by", "o stroke", "u grave",
<------> "u acute",
/* 251 */ "u circumflex", "u oomlaut", "y acute", "thorn", "y oomlaut"
};
/* array of 256 u_short (one for each character)
* initialized to default_chartab and user selectable via
* /sys/module/speakup/parameters/chartab
*/
u_short spk_chartab[256];
static u_short default_chartab[256] = {
<------>B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 0-7 */
<------>B_CTL, B_CTL, A_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 8-15 */
<------>B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /*16-23 */
<------>B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, B_CTL, /* 24-31 */
<------>WDLM, A_PUNC, PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* !"#$%&' */
<------>PUNC, PUNC, PUNC, PUNC, A_PUNC, A_PUNC, A_PUNC, PUNC, /* ()*+, -./ */
<------>NUM, NUM, NUM, NUM, NUM, NUM, NUM, NUM, /* 01234567 */
<------>NUM, NUM, A_PUNC, PUNC, PUNC, PUNC, PUNC, A_PUNC, /* 89:;<=>? */
<------>PUNC, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* @ABCDEFG */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* HIJKLMNO */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* PQRSTUVW */
<------>A_CAP, A_CAP, A_CAP, PUNC, PUNC, PUNC, PUNC, PUNC, /* XYZ[\]^_ */
<------>PUNC, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* `abcdefg */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* hijklmno */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* pqrstuvw */
<------>ALPHA, ALPHA, ALPHA, PUNC, PUNC, PUNC, PUNC, 0, /* xyz{|}~ */
<------>B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 128-134 */
<------>B_SYM, /* 135 */
<------>B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 136-142 */
<------>B_CAPSYM, /* 143 */
<------>B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /* 144-150 */
<------>B_SYM, /* 151 */
<------>B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, /*152-158 */
<------>B_SYM, /* 159 */
<------>WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 160-166 */
<------>B_SYM, /* 167 */
<------>B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 168-175 */
<------>B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 176-183 */
<------>B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 184-191 */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 192-199 */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, /* 200-207 */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, B_SYM, /* 208-215 */
<------>A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, A_CAP, ALPHA, /* 216-223 */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 224-231 */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, /* 232-239 */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, B_SYM, /* 240-247 */
<------>ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA /* 248-255 */
};
struct task_struct *speakup_task;
struct bleep spk_unprocessed_sound;
static int spk_keydown;
static u16 spk_lastkey;
static u_char spk_close_press, keymap_flags;
static u_char last_keycode, this_speakup_key;
static u_long last_spk_jiffy;
struct st_spk_t *speakup_console[MAX_NR_CONSOLES];
DEFINE_MUTEX(spk_mutex);
static int keyboard_notifier_call(struct notifier_block *,
<------><------><------><------> unsigned long code, void *param);
static struct notifier_block keyboard_notifier_block = {
<------>.notifier_call = keyboard_notifier_call,
};
static int vt_notifier_call(struct notifier_block *,
<------><------><------> unsigned long code, void *param);
static struct notifier_block vt_notifier_block = {
<------>.notifier_call = vt_notifier_call,
};
static unsigned char get_attributes(struct vc_data *vc, u16 *pos)
{
<------>pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
<------>return (scr_readw(pos) & ~vc->vc_hi_font_mask) >> 8;
}
static void speakup_date(struct vc_data *vc)
{
<------>spk_x = spk_cx = vc->state.x;
<------>spk_y = spk_cy = vc->state.y;
<------>spk_pos = spk_cp = vc->vc_pos;
<------>spk_old_attr = spk_attr;
<------>spk_attr = get_attributes(vc, (u_short *)spk_pos);
}
static void bleep(u_short val)
{
<------>static const short vals[] = {
<------><------>350, 370, 392, 414, 440, 466, 491, 523, 554, 587, 619, 659
<------>};
<------>short freq;
<------>int time = spk_bleep_time;
<------>freq = vals[val % 12];
<------>if (val > 11)
<------><------>freq *= (1 << (val / 12));
<------>spk_unprocessed_sound.freq = freq;
<------>spk_unprocessed_sound.jiffies = msecs_to_jiffies(time);
<------>spk_unprocessed_sound.active = 1;
<------>/* We can only have 1 active sound at a time. */
}
static void speakup_shut_up(struct vc_data *vc)
{
<------>if (spk_killed)
<------><------>return;
<------>spk_shut_up |= 0x01;
<------>spk_parked &= 0xfe;
<------>speakup_date(vc);
<------>if (synth)
<------><------>spk_do_flush();
}
static void speech_kill(struct vc_data *vc)
{
<------>char val = synth->is_alive(synth);
<------>if (val == 0)
<------><------>return;
<------>/* re-enables synth, if disabled */
<------>if (val == 2 || spk_killed) {
<------><------>/* dead */
<------><------>spk_shut_up &= ~0x40;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_IAM_ALIVE));
<------>} else {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_YOU_KILLED_SPEAKUP));
<------><------>spk_shut_up |= 0x40;
<------>}
}
static void speakup_off(struct vc_data *vc)
{
<------>if (spk_shut_up & 0x80) {
<------><------>spk_shut_up &= 0x7f;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_HEY_THATS_BETTER));
<------>} else {
<------><------>spk_shut_up |= 0x80;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_YOU_TURNED_ME_OFF));
<------>}
<------>speakup_date(vc);
}
static void speakup_parked(struct vc_data *vc)
{
<------>if (spk_parked & 0x80) {
<------><------>spk_parked = 0;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_UNPARKED));
<------>} else {
<------><------>spk_parked |= 0x80;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_PARKED));
<------>}
}
static void speakup_cut(struct vc_data *vc)
{
<------>static const char err_buf[] = "set selection failed";
<------>int ret;
<------>if (!mark_cut_flag) {
<------><------>mark_cut_flag = 1;
<------><------>spk_xs = (u_short)spk_x;
<------><------>spk_ys = (u_short)spk_y;
<------><------>spk_sel_cons = vc;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_MARK));
<------><------>return;
<------>}
<------>spk_xe = (u_short)spk_x;
<------>spk_ye = (u_short)spk_y;
<------>mark_cut_flag = 0;
<------>synth_printf("%s\n", spk_msg_get(MSG_CUT));
<------>ret = speakup_set_selection(tty);
<------>switch (ret) {
<------>case 0:
<------><------>break; /* no error */
<------>case -EFAULT:
<------><------>pr_warn("%sEFAULT\n", err_buf);
<------><------>break;
<------>case -EINVAL:
<------><------>pr_warn("%sEINVAL\n", err_buf);
<------><------>break;
<------>case -ENOMEM:
<------><------>pr_warn("%sENOMEM\n", err_buf);
<------><------>break;
<------>}
}
static void speakup_paste(struct vc_data *vc)
{
<------>if (mark_cut_flag) {
<------><------>mark_cut_flag = 0;
<------><------>synth_printf("%s\n", spk_msg_get(MSG_MARK_CLEARED));
<------>} else {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_PASTE));
<------><------>speakup_paste_selection(tty);
<------>}
}
static void say_attributes(struct vc_data *vc)
{
<------>int fg = spk_attr & 0x0f;
<------>int bg = spk_attr >> 4;
<------>if (fg > 8) {
<------><------>synth_printf("%s ", spk_msg_get(MSG_BRIGHT));
<------><------>fg -= 8;
<------>}
<------>synth_printf("%s", spk_msg_get(MSG_COLORS_START + fg));
<------>if (bg > 7) {
<------><------>synth_printf(" %s ", spk_msg_get(MSG_ON_BLINKING));
<------><------>bg -= 8;
<------>} else {
<------><------>synth_printf(" %s ", spk_msg_get(MSG_ON));
<------>}
<------>synth_printf("%s\n", spk_msg_get(MSG_COLORS_START + bg));
}
enum {
<------>edge_top = 1,
<------>edge_bottom,
<------>edge_left,
<------>edge_right,
<------>edge_quiet
};
static void announce_edge(struct vc_data *vc, int msg_id)
{
<------>if (spk_bleeps & 1)
<------><------>bleep(spk_y);
<------>if ((spk_bleeps & 2) && (msg_id < edge_quiet))
<------><------>synth_printf("%s\n",
<------><------><------> spk_msg_get(MSG_EDGE_MSGS_START + msg_id - 1));
}
static void speak_char(u16 ch)
{
<------>char *cp;
<------>struct var_t *direct = spk_get_var(DIRECT);
<------>if (ch >= 0x100 || (direct && direct->u.n.value)) {
<------><------>if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
<------><------><------>spk_pitch_shift++;
<------><------><------>synth_printf("%s", spk_str_caps_start);
<------><------>}
<------><------>synth_putwc_s(ch);
<------><------>if (ch < 0x100 && IS_CHAR(ch, B_CAP))
<------><------><------>synth_printf("%s", spk_str_caps_stop);
<------><------>return;
<------>}
<------>cp = spk_characters[ch];
<------>if (!cp) {
<------><------>pr_info("%s: cp == NULL!\n", __func__);
<------><------>return;
<------>}
<------>if (IS_CHAR(ch, B_CAP)) {
<------><------>spk_pitch_shift++;
<------><------>synth_printf("%s %s %s",
<------><------><------> spk_str_caps_start, cp, spk_str_caps_stop);
<------>} else {
<------><------>if (*cp == '^') {
<------><------><------>cp++;
<------><------><------>synth_printf(" %s%s ", spk_msg_get(MSG_CTRL), cp);
<------><------>} else {
<------><------><------>synth_printf(" %s ", cp);
<------><------>}
<------>}
}
static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs)
{
<------>u16 ch = ' ';
<------>if (vc && pos) {
<------><------>u16 w;
<------><------>u16 c;
<------><------>pos = screen_pos(vc, pos - (u16 *)vc->vc_origin, true);
<------><------>w = scr_readw(pos);
<------><------>c = w & 0xff;
<------><------>if (w & vc->vc_hi_font_mask) {
<------><------><------>w &= ~vc->vc_hi_font_mask;
<------><------><------>c |= 0x100;
<------><------>}
<------><------>ch = inverse_translate(vc, c, 1);
<------><------>*attribs = (w & 0xff00) >> 8;
<------>}
<------>return ch;
}
static void say_char(struct vc_data *vc)
{
<------>u16 ch;
<------>spk_old_attr = spk_attr;
<------>ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
<------>if (spk_attr != spk_old_attr) {
<------><------>if (spk_attrib_bleep & 1)
<------><------><------>bleep(spk_y);
<------><------>if (spk_attrib_bleep & 2)
<------><------><------>say_attributes(vc);
<------>}
<------>speak_char(ch);
}
static void say_phonetic_char(struct vc_data *vc)
{
<------>u16 ch;
<------>spk_old_attr = spk_attr;
<------>ch = get_char(vc, (u_short *)spk_pos, &spk_attr);
<------>if (ch <= 0x7f && isalpha(ch)) {
<------><------>ch &= 0x1f;
<------><------>synth_printf("%s\n", phonetic[--ch]);
<------>} else {
<------><------>if (ch < 0x100 && IS_CHAR(ch, B_NUM))
<------><------><------>synth_printf("%s ", spk_msg_get(MSG_NUMBER));
<------><------>speak_char(ch);
<------>}
}
static void say_prev_char(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>if (spk_x == 0) {
<------><------>announce_edge(vc, edge_left);
<------><------>return;
<------>}
<------>spk_x--;
<------>spk_pos -= 2;
<------>say_char(vc);
}
static void say_next_char(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>if (spk_x == vc->vc_cols - 1) {
<------><------>announce_edge(vc, edge_right);
<------><------>return;
<------>}
<------>spk_x++;
<------>spk_pos += 2;
<------>say_char(vc);
}
/* get_word - will first check to see if the character under the
* reading cursor is a space and if spk_say_word_ctl is true it will
* return the word space. If spk_say_word_ctl is not set it will check to
* see if there is a word starting on the next position to the right
* and return that word if it exists. If it does not exist it will
* move left to the beginning of any previous word on the line or the
* beginning off the line whichever comes first..
*/
static u_long get_word(struct vc_data *vc)
{
<------>u_long cnt = 0, tmpx = spk_x, tmp_pos = spk_pos;
<------>u16 ch;
<------>u16 attr_ch;
<------>u_char temp;
<------>spk_old_attr = spk_attr;
<------>ch = get_char(vc, (u_short *)tmp_pos, &temp);
/* decided to take out the sayword if on a space (mis-information */
<------>if (spk_say_word_ctl && ch == SPACE) {
<------><------>*buf = '\0';
<------><------>synth_printf("%s\n", spk_msg_get(MSG_SPACE));
<------><------>return 0;
<------>} else if (tmpx < vc->vc_cols - 2 &&
<------><------> (ch == SPACE || ch == 0 || (ch < 0x100 && IS_WDLM(ch))) &&
<------><------> get_char(vc, (u_short *)tmp_pos + 1, &temp) > SPACE) {
<------><------>tmp_pos += 2;
<------><------>tmpx++;
<------>} else {
<------><------>while (tmpx > 0) {
<------><------><------>ch = get_char(vc, (u_short *)tmp_pos - 1, &temp);
<------><------><------>if ((ch == SPACE || ch == 0 ||
<------><------><------> (ch < 0x100 && IS_WDLM(ch))) &&
<------><------><------> get_char(vc, (u_short *)tmp_pos, &temp) > SPACE)
<------><------><------><------>break;
<------><------><------>tmp_pos -= 2;
<------><------><------>tmpx--;
<------><------>}
<------>}
<------>attr_ch = get_char(vc, (u_short *)tmp_pos, &spk_attr);
<------>buf[cnt++] = attr_ch;
<------>while (tmpx < vc->vc_cols - 1) {
<------><------>tmp_pos += 2;
<------><------>tmpx++;
<------><------>ch = get_char(vc, (u_short *)tmp_pos, &temp);
<------><------>if (ch == SPACE || ch == 0 ||
<------><------> (buf[cnt - 1] < 0x100 && IS_WDLM(buf[cnt - 1]) &&
<------><------> ch > SPACE))
<------><------><------>break;
<------><------>buf[cnt++] = ch;
<------>}
<------>buf[cnt] = '\0';
<------>return cnt;
}
static void say_word(struct vc_data *vc)
{
<------>u_long cnt = get_word(vc);
<------>u_short saved_punc_mask = spk_punc_mask;
<------>if (cnt == 0)
<------><------>return;
<------>spk_punc_mask = PUNC;
<------>buf[cnt++] = SPACE;
<------>spkup_write(buf, cnt);
<------>spk_punc_mask = saved_punc_mask;
}
static void say_prev_word(struct vc_data *vc)
{
<------>u_char temp;
<------>u16 ch;
<------>u_short edge_said = 0, last_state = 0, state = 0;
<------>spk_parked |= 0x01;
<------>if (spk_x == 0) {
<------><------>if (spk_y == 0) {
<------><------><------>announce_edge(vc, edge_top);
<------><------><------>return;
<------><------>}
<------><------>spk_y--;
<------><------>spk_x = vc->vc_cols;
<------><------>edge_said = edge_quiet;
<------>}
<------>while (1) {
<------><------>if (spk_x == 0) {
<------><------><------>if (spk_y == 0) {
<------><------><------><------>edge_said = edge_top;
<------><------><------><------>break;
<------><------><------>}
<------><------><------>if (edge_said != edge_quiet)
<------><------><------><------>edge_said = edge_left;
<------><------><------>if (state > 0)
<------><------><------><------>break;
<------><------><------>spk_y--;
<------><------><------>spk_x = vc->vc_cols - 1;
<------><------>} else {
<------><------><------>spk_x--;
<------><------>}
<------><------>spk_pos -= 2;
<------><------>ch = get_char(vc, (u_short *)spk_pos, &temp);
<------><------>if (ch == SPACE || ch == 0)
<------><------><------>state = 0;
<------><------>else if (ch < 0x100 && IS_WDLM(ch))
<------><------><------>state = 1;
<------><------>else
<------><------><------>state = 2;
<------><------>if (state < last_state) {
<------><------><------>spk_pos += 2;
<------><------><------>spk_x++;
<------><------><------>break;
<------><------>}
<------><------>last_state = state;
<------>}
<------>if (spk_x == 0 && edge_said == edge_quiet)
<------><------>edge_said = edge_left;
<------>if (edge_said > 0 && edge_said < edge_quiet)
<------><------>announce_edge(vc, edge_said);
<------>say_word(vc);
}
static void say_next_word(struct vc_data *vc)
{
<------>u_char temp;
<------>u16 ch;
<------>u_short edge_said = 0, last_state = 2, state = 0;
<------>spk_parked |= 0x01;
<------>if (spk_x == vc->vc_cols - 1 && spk_y == vc->vc_rows - 1) {
<------><------>announce_edge(vc, edge_bottom);
<------><------>return;
<------>}
<------>while (1) {
<------><------>ch = get_char(vc, (u_short *)spk_pos, &temp);
<------><------>if (ch == SPACE || ch == 0)
<------><------><------>state = 0;
<------><------>else if (ch < 0x100 && IS_WDLM(ch))
<------><------><------>state = 1;
<------><------>else
<------><------><------>state = 2;
<------><------>if (state > last_state)
<------><------><------>break;
<------><------>if (spk_x >= vc->vc_cols - 1) {
<------><------><------>if (spk_y == vc->vc_rows - 1) {
<------><------><------><------>edge_said = edge_bottom;
<------><------><------><------>break;
<------><------><------>}
<------><------><------>state = 0;
<------><------><------>spk_y++;
<------><------><------>spk_x = 0;
<------><------><------>edge_said = edge_right;
<------><------>} else {
<------><------><------>spk_x++;
<------><------>}
<------><------>spk_pos += 2;
<------><------>last_state = state;
<------>}
<------>if (edge_said > 0)
<------><------>announce_edge(vc, edge_said);
<------>say_word(vc);
}
static void spell_word(struct vc_data *vc)
{
<------>static char const *delay_str[] = { "", ",", ".", ". .", ". . ." };
<------>u16 *cp = buf;
<------>char *cp1;
<------>char *str_cap = spk_str_caps_stop;
<------>char *last_cap = spk_str_caps_stop;
<------>struct var_t *direct = spk_get_var(DIRECT);
<------>u16 ch;
<------>if (!get_word(vc))
<------><------>return;
<------>while ((ch = *cp)) {
<------><------>if (cp != buf)
<------><------><------>synth_printf(" %s ", delay_str[spk_spell_delay]);
<------><------>/* FIXME: Non-latin1 considered as lower case */
<------><------>if (ch < 0x100 && IS_CHAR(ch, B_CAP)) {
<------><------><------>str_cap = spk_str_caps_start;
<------><------><------>if (*spk_str_caps_stop)
<------><------><------><------>spk_pitch_shift++;
<------><------><------>else /* synth has no pitch */
<------><------><------><------>last_cap = spk_str_caps_stop;
<------><------>} else {
<------><------><------>str_cap = spk_str_caps_stop;
<------><------>}
<------><------>if (str_cap != last_cap) {
<------><------><------>synth_printf("%s", str_cap);
<------><------><------>last_cap = str_cap;
<------><------>}
<------><------>if (ch >= 0x100 || (direct && direct->u.n.value)) {
<------><------><------>synth_putwc_s(ch);
<------><------>} else if (this_speakup_key == SPELL_PHONETIC &&
<------><------> ch <= 0x7f && isalpha(ch)) {
<------><------><------>ch &= 0x1f;
<------><------><------>cp1 = phonetic[--ch];
<------><------><------>synth_printf("%s", cp1);
<------><------>} else {
<------><------><------>cp1 = spk_characters[ch];
<------><------><------>if (*cp1 == '^') {
<------><------><------><------>synth_printf("%s", spk_msg_get(MSG_CTRL));
<------><------><------><------>cp1++;
<------><------><------>}
<------><------><------>synth_printf("%s", cp1);
<------><------>}
<------><------>cp++;
<------>}
<------>if (str_cap != spk_str_caps_stop)
<------><------>synth_printf("%s", spk_str_caps_stop);
}
static int get_line(struct vc_data *vc)
{
<------>u_long tmp = spk_pos - (spk_x * 2);
<------>int i = 0;
<------>u_char tmp2;
<------>spk_old_attr = spk_attr;
<------>spk_attr = get_attributes(vc, (u_short *)spk_pos);
<------>for (i = 0; i < vc->vc_cols; i++) {
<------><------>buf[i] = get_char(vc, (u_short *)tmp, &tmp2);
<------><------>tmp += 2;
<------>}
<------>for (--i; i >= 0; i--)
<------><------>if (buf[i] != SPACE)
<------><------><------>break;
<------>return ++i;
}
static void say_line(struct vc_data *vc)
{
<------>int i = get_line(vc);
<------>u16 *cp;
<------>u_short saved_punc_mask = spk_punc_mask;
<------>if (i == 0) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_BLANK));
<------><------>return;
<------>}
<------>buf[i++] = '\n';
<------>if (this_speakup_key == SAY_LINE_INDENT) {
<------><------>cp = buf;
<------><------>while (*cp == SPACE)
<------><------><------>cp++;
<------><------>synth_printf("%zd, ", (cp - buf) + 1);
<------>}
<------>spk_punc_mask = spk_punc_masks[spk_reading_punc];
<------>spkup_write(buf, i);
<------>spk_punc_mask = saved_punc_mask;
}
static void say_prev_line(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>if (spk_y == 0) {
<------><------>announce_edge(vc, edge_top);
<------><------>return;
<------>}
<------>spk_y--;
<------>spk_pos -= vc->vc_size_row;
<------>say_line(vc);
}
static void say_next_line(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>if (spk_y == vc->vc_rows - 1) {
<------><------>announce_edge(vc, edge_bottom);
<------><------>return;
<------>}
<------>spk_y++;
<------>spk_pos += vc->vc_size_row;
<------>say_line(vc);
}
static int say_from_to(struct vc_data *vc, u_long from, u_long to,
<------><------> int read_punc)
{
<------>int i = 0;
<------>u_char tmp;
<------>u_short saved_punc_mask = spk_punc_mask;
<------>spk_old_attr = spk_attr;
<------>spk_attr = get_attributes(vc, (u_short *)from);
<------>while (from < to) {
<------><------>buf[i++] = get_char(vc, (u_short *)from, &tmp);
<------><------>from += 2;
<------><------>if (i >= vc->vc_size_row)
<------><------><------>break;
<------>}
<------>for (--i; i >= 0; i--)
<------><------>if (buf[i] != SPACE)
<------><------><------>break;
<------>buf[++i] = SPACE;
<------>buf[++i] = '\0';
<------>if (i < 1)
<------><------>return i;
<------>if (read_punc)
<------><------>spk_punc_mask = spk_punc_info[spk_reading_punc].mask;
<------>spkup_write(buf, i);
<------>if (read_punc)
<------><------>spk_punc_mask = saved_punc_mask;
<------>return i - 1;
}
static void say_line_from_to(struct vc_data *vc, u_long from, u_long to,
<------><------><------> int read_punc)
{
<------>u_long start = vc->vc_origin + (spk_y * vc->vc_size_row);
<------>u_long end = start + (to * 2);
<------>start += from * 2;
<------>if (say_from_to(vc, start, end, read_punc) <= 0)
<------><------>if (cursor_track != read_all_mode)
<------><------><------>synth_printf("%s\n", spk_msg_get(MSG_BLANK));
}
/* Sentence Reading Commands */
static int currsentence;
static int numsentences[2];
static u16 *sentbufend[2];
static u16 *sentmarks[2][10];
static int currbuf;
static int bn;
static u16 sentbuf[2][256];
static int say_sentence_num(int num, int prev)
{
<------>bn = currbuf;
<------>currsentence = num + 1;
<------>if (prev && --bn == -1)
<------><------>bn = 1;
<------>if (num > numsentences[bn])
<------><------>return 0;
<------>spkup_write(sentmarks[bn][num], sentbufend[bn] - sentmarks[bn][num]);
<------>return 1;
}
static int get_sentence_buf(struct vc_data *vc, int read_punc)
{
<------>u_long start, end;
<------>int i, bn;
<------>u_char tmp;
<------>currbuf++;
<------>if (currbuf == 2)
<------><------>currbuf = 0;
<------>bn = currbuf;
<------>start = vc->vc_origin + ((spk_y) * vc->vc_size_row);
<------>end = vc->vc_origin + ((spk_y) * vc->vc_size_row) + vc->vc_cols * 2;
<------>numsentences[bn] = 0;
<------>sentmarks[bn][0] = &sentbuf[bn][0];
<------>i = 0;
<------>spk_old_attr = spk_attr;
<------>spk_attr = get_attributes(vc, (u_short *)start);
<------>while (start < end) {
<------><------>sentbuf[bn][i] = get_char(vc, (u_short *)start, &tmp);
<------><------>if (i > 0) {
<------><------><------>if (sentbuf[bn][i] == SPACE &&
<------><------><------> sentbuf[bn][i - 1] == '.' &&
<------><------><------> numsentences[bn] < 9) {
<------><------><------><------>/* Sentence Marker */
<------><------><------><------>numsentences[bn]++;
<------><------><------><------>sentmarks[bn][numsentences[bn]] =
<------><------><------><------> &sentbuf[bn][i];
<------><------><------>}
<------><------>}
<------><------>i++;
<------><------>start += 2;
<------><------>if (i >= vc->vc_size_row)
<------><------><------>break;
<------>}
<------>for (--i; i >= 0; i--)
<------><------>if (sentbuf[bn][i] != SPACE)
<------><------><------>break;
<------>if (i < 1)
<------><------>return -1;
<------>sentbuf[bn][++i] = SPACE;
<------>sentbuf[bn][++i] = '\0';
<------>sentbufend[bn] = &sentbuf[bn][i];
<------>return numsentences[bn];
}
static void say_screen_from_to(struct vc_data *vc, u_long from, u_long to)
{
<------>u_long start = vc->vc_origin, end;
<------>if (from > 0)
<------><------>start += from * vc->vc_size_row;
<------>if (to > vc->vc_rows)
<------><------>to = vc->vc_rows;
<------>end = vc->vc_origin + (to * vc->vc_size_row);
<------>for (from = start; from < end; from = to) {
<------><------>to = from + vc->vc_size_row;
<------><------>say_from_to(vc, from, to, 1);
<------>}
}
static void say_screen(struct vc_data *vc)
{
<------>say_screen_from_to(vc, 0, vc->vc_rows);
}
static void speakup_win_say(struct vc_data *vc)
{
<------>u_long start, end, from, to;
<------>if (win_start < 2) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
<------><------>return;
<------>}
<------>start = vc->vc_origin + (win_top * vc->vc_size_row);
<------>end = vc->vc_origin + (win_bottom * vc->vc_size_row);
<------>while (start <= end) {
<------><------>from = start + (win_left * 2);
<------><------>to = start + (win_right * 2);
<------><------>say_from_to(vc, from, to, 1);
<------><------>start += vc->vc_size_row;
<------>}
}
static void top_edge(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>spk_pos = vc->vc_origin + 2 * spk_x;
<------>spk_y = 0;
<------>say_line(vc);
}
static void bottom_edge(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>spk_pos += (vc->vc_rows - spk_y - 1) * vc->vc_size_row;
<------>spk_y = vc->vc_rows - 1;
<------>say_line(vc);
}
static void left_edge(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>spk_pos -= spk_x * 2;
<------>spk_x = 0;
<------>say_char(vc);
}
static void right_edge(struct vc_data *vc)
{
<------>spk_parked |= 0x01;
<------>spk_pos += (vc->vc_cols - spk_x - 1) * 2;
<------>spk_x = vc->vc_cols - 1;
<------>say_char(vc);
}
static void say_first_char(struct vc_data *vc)
{
<------>int i, len = get_line(vc);
<------>u16 ch;
<------>spk_parked |= 0x01;
<------>if (len == 0) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_BLANK));
<------><------>return;
<------>}
<------>for (i = 0; i < len; i++)
<------><------>if (buf[i] != SPACE)
<------><------><------>break;
<------>ch = buf[i];
<------>spk_pos -= (spk_x - i) * 2;
<------>spk_x = i;
<------>synth_printf("%d, ", ++i);
<------>speak_char(ch);
}
static void say_last_char(struct vc_data *vc)
{
<------>int len = get_line(vc);
<------>u16 ch;
<------>spk_parked |= 0x01;
<------>if (len == 0) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_BLANK));
<------><------>return;
<------>}
<------>ch = buf[--len];
<------>spk_pos -= (spk_x - len) * 2;
<------>spk_x = len;
<------>synth_printf("%d, ", ++len);
<------>speak_char(ch);
}
static void say_position(struct vc_data *vc)
{
<------>synth_printf(spk_msg_get(MSG_POS_INFO), spk_y + 1, spk_x + 1,
<------><------> vc->vc_num + 1);
<------>synth_printf("\n");
}
/* Added by brianb */
static void say_char_num(struct vc_data *vc)
{
<------>u_char tmp;
<------>u16 ch = get_char(vc, (u_short *)spk_pos, &tmp);
<------>synth_printf(spk_msg_get(MSG_CHAR_INFO), ch, ch);
}
/* these are stub functions to keep keyboard.c happy. */
static void say_from_top(struct vc_data *vc)
{
<------>say_screen_from_to(vc, 0, spk_y);
}
static void say_to_bottom(struct vc_data *vc)
{
<------>say_screen_from_to(vc, spk_y, vc->vc_rows);
}
static void say_from_left(struct vc_data *vc)
{
<------>say_line_from_to(vc, 0, spk_x, 1);
}
static void say_to_right(struct vc_data *vc)
{
<------>say_line_from_to(vc, spk_x, vc->vc_cols, 1);
}
/* end of stub functions. */
static void spkup_write(const u16 *in_buf, int count)
{
<------>static int rep_count;
<------>static u16 ch = '\0', old_ch = '\0';
<------>static u_short char_type, last_type;
<------>int in_count = count;
<------>spk_keydown = 0;
<------>while (count--) {
<------><------>if (cursor_track == read_all_mode) {
<------><------><------>/* Insert Sentence Index */
<------><------><------>if ((in_buf == sentmarks[bn][currsentence]) &&
<------><------><------> (currsentence <= numsentences[bn]))
<------><------><------><------>synth_insert_next_index(currsentence++);
<------><------>}
<------><------>ch = *in_buf++;
<------><------>if (ch < 0x100)
<------><------><------>char_type = spk_chartab[ch];
<------><------>else
<------><------><------>char_type = ALPHA;
<------><------>if (ch == old_ch && !(char_type & B_NUM)) {
<------><------><------>if (++rep_count > 2)
<------><------><------><------>continue;
<------><------>} else {
<------><------><------>if ((last_type & CH_RPT) && rep_count > 2) {
<------><------><------><------>synth_printf(" ");
<------><------><------><------>synth_printf(spk_msg_get(MSG_REPEAT_DESC),
<------><------><------><------><------> ++rep_count);
<------><------><------><------>synth_printf(" ");
<------><------><------>}
<------><------><------>rep_count = 0;
<------><------>}
<------><------>if (ch == spk_lastkey) {
<------><------><------>rep_count = 0;
<------><------><------>if (spk_key_echo == 1 && ch >= MINECHOCHAR)
<------><------><------><------>speak_char(ch);
<------><------>} else if (char_type & B_ALPHA) {
<------><------><------>if ((synth_flags & SF_DEC) && (last_type & PUNC))
<------><------><------><------>synth_buffer_add(SPACE);
<------><------><------>synth_putwc_s(ch);
<------><------>} else if (char_type & B_NUM) {
<------><------><------>rep_count = 0;
<------><------><------>synth_putwc_s(ch);
<------><------>} else if (char_type & spk_punc_mask) {
<------><------><------>speak_char(ch);
<------><------><------>char_type &= ~PUNC; /* for dec nospell processing */
<------><------>} else if (char_type & SYNTH_OK) {
<------><------><------>/* these are usually puncts like . and , which synth
<------><------><------> * needs for expression.
<------><------><------> * suppress multiple to get rid of long pauses and
<------><------><------> * clear repeat count
<------><------><------> * so if someone has
<------><------><------> * repeats on you don't get nothing repeated count
<------><------><------> */
<------><------><------>if (ch != old_ch)
<------><------><------><------>synth_putwc_s(ch);
<------><------><------>else
<------><------><------><------>rep_count = 0;
<------><------>} else {
/* send space and record position, if next is num overwrite space */
<------><------><------>if (old_ch != ch)
<------><------><------><------>synth_buffer_add(SPACE);
<------><------><------>else
<------><------><------><------>rep_count = 0;
<------><------>}
<------><------>old_ch = ch;
<------><------>last_type = char_type;
<------>}
<------>spk_lastkey = 0;
<------>if (in_count > 2 && rep_count > 2) {
<------><------>if (last_type & CH_RPT) {
<------><------><------>synth_printf(" ");
<------><------><------>synth_printf(spk_msg_get(MSG_REPEAT_DESC2),
<------><------><------><------> ++rep_count);
<------><------><------>synth_printf(" ");
<------><------>}
<------><------>rep_count = 0;
<------>}
}
static const int NUM_CTL_LABELS = (MSG_CTL_END - MSG_CTL_START + 1);
static void read_all_doc(struct vc_data *vc);
static void cursor_done(struct timer_list *unused);
static DEFINE_TIMER(cursor_timer, cursor_done);
static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag)
{
<------>unsigned long flags;
<------>if (!synth || up_flag || spk_killed)
<------><------>return;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>if (cursor_track == read_all_mode) {
<------><------>switch (value) {
<------><------>case KVAL(K_SHIFT):
<------><------><------>del_timer(&cursor_timer);
<------><------><------>spk_shut_up &= 0xfe;
<------><------><------>spk_do_flush();
<------><------><------>read_all_doc(vc);
<------><------><------>break;
<------><------>case KVAL(K_CTRL):
<------><------><------>del_timer(&cursor_timer);
<------><------><------>cursor_track = prev_cursor_track;
<------><------><------>spk_shut_up &= 0xfe;
<------><------><------>spk_do_flush();
<------><------><------>break;
<------><------>}
<------>} else {
<------><------>spk_shut_up &= 0xfe;
<------><------>spk_do_flush();
<------>}
<------>if (spk_say_ctrl && value < NUM_CTL_LABELS)
<------><------>synth_printf("%s", spk_msg_get(MSG_CTL_START + value));
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag)
{
<------>unsigned long flags;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>if (up_flag) {
<------><------>spk_lastkey = 0;
<------><------>spk_keydown = 0;
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>if (!synth || spk_killed) {
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>spk_shut_up &= 0xfe;
<------>spk_lastkey = value;
<------>spk_keydown++;
<------>spk_parked &= 0xfe;
<------>if (spk_key_echo == 2 && value >= MINECHOCHAR)
<------><------>speak_char(value);
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
int spk_set_key_info(const u_char *key_info, u_char *k_buffer)
{
<------>int i = 0, states, key_data_len;
<------>const u_char *cp = key_info;
<------>u_char *cp1 = k_buffer;
<------>u_char ch, version, num_keys;
<------>version = *cp++;
<------>if (version != KEY_MAP_VER) {
<------><------>pr_debug("version found %d should be %d\n",
<------><------><------> version, KEY_MAP_VER);
<------><------>return -EINVAL;
<------>}
<------>num_keys = *cp;
<------>states = (int)cp[1];
<------>key_data_len = (states + 1) * (num_keys + 1);
<------>if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(spk_key_buf)) {
<------><------>pr_debug("too many key_infos (%d over %u)\n",
<------><------><------> key_data_len + SHIFT_TBL_SIZE + 4,
<------><------><------> (unsigned int)(sizeof(spk_key_buf)));
<------><------>return -EINVAL;
<------>}
<------>memset(k_buffer, 0, SHIFT_TBL_SIZE);
<------>memset(spk_our_keys, 0, sizeof(spk_our_keys));
<------>spk_shift_table = k_buffer;
<------>spk_our_keys[0] = spk_shift_table;
<------>cp1 += SHIFT_TBL_SIZE;
<------>memcpy(cp1, cp, key_data_len + 3);
<------>/* get num_keys, states and data */
<------>cp1 += 2; /* now pointing at shift states */
<------>for (i = 1; i <= states; i++) {
<------><------>ch = *cp1++;
<------><------>if (ch >= SHIFT_TBL_SIZE) {
<------><------><------>pr_debug("(%d) not valid shift state (max_allowed = %d)\n",
<------><------><------><------> ch, SHIFT_TBL_SIZE);
<------><------><------>return -EINVAL;
<------><------>}
<------><------>spk_shift_table[ch] = i;
<------>}
<------>keymap_flags = *cp1++;
<------>while ((ch = *cp1)) {
<------><------>if (ch >= MAX_KEY) {
<------><------><------>pr_debug("(%d), not valid key, (max_allowed = %d)\n",
<------><------><------><------> ch, MAX_KEY);
<------><------><------>return -EINVAL;
<------><------>}
<------><------>spk_our_keys[ch] = cp1;
<------><------>cp1 += states + 1;
<------>}
<------>return 0;
}
static struct var_t spk_vars[] = {
<------>/* bell must be first to set high limit */
<------>{BELL_POS, .u.n = {NULL, 0, 0, 0, 0, 0, NULL} },
<------>{SPELL_DELAY, .u.n = {NULL, 0, 0, 4, 0, 0, NULL} },
<------>{ATTRIB_BLEEP, .u.n = {NULL, 1, 0, 3, 0, 0, NULL} },
<------>{BLEEPS, .u.n = {NULL, 3, 0, 3, 0, 0, NULL} },
<------>{BLEEP_TIME, .u.n = {NULL, 30, 1, 200, 0, 0, NULL} },
<------>{PUNC_LEVEL, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
<------>{READING_PUNC, .u.n = {NULL, 1, 0, 4, 0, 0, NULL} },
<------>{CURSOR_TIME, .u.n = {NULL, 120, 50, 600, 0, 0, NULL} },
<------>{SAY_CONTROL, TOGGLE_0},
<------>{SAY_WORD_CTL, TOGGLE_0},
<------>{NO_INTERRUPT, TOGGLE_0},
<------>{KEY_ECHO, .u.n = {NULL, 1, 0, 2, 0, 0, NULL} },
<------>V_LAST_VAR
};
static void toggle_cursoring(struct vc_data *vc)
{
<------>if (cursor_track == read_all_mode)
<------><------>cursor_track = prev_cursor_track;
<------>if (++cursor_track >= CT_Max)
<------><------>cursor_track = 0;
<------>synth_printf("%s\n", spk_msg_get(MSG_CURSOR_MSGS_START + cursor_track));
}
void spk_reset_default_chars(void)
{
<------>int i;
<------>/* First, free any non-default */
<------>for (i = 0; i < 256; i++) {
<------><------>if (spk_characters[i] &&
<------><------> (spk_characters[i] != spk_default_chars[i]))
<------><------><------>kfree(spk_characters[i]);
<------>}
<------>memcpy(spk_characters, spk_default_chars, sizeof(spk_default_chars));
}
void spk_reset_default_chartab(void)
{
<------>memcpy(spk_chartab, default_chartab, sizeof(default_chartab));
}
static const struct st_bits_data *pb_edit;
static int edit_bits(struct vc_data *vc, u_char type, u_char ch, u_short key)
{
<------>short mask = pb_edit->mask, ch_type = spk_chartab[ch];
<------>if (type != KT_LATIN || (ch_type & B_NUM) || ch < SPACE)
<------><------>return -1;
<------>if (ch == SPACE) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_EDIT_DONE));
<------><------>spk_special_handler = NULL;
<------><------>return 1;
<------>}
<------>if (mask < PUNC && !(ch_type & PUNC))
<------><------>return -1;
<------>spk_chartab[ch] ^= mask;
<------>speak_char(ch);
<------>synth_printf(" %s\n",
<------><------> (spk_chartab[ch] & mask) ? spk_msg_get(MSG_ON) :
<------><------> spk_msg_get(MSG_OFF));
<------>return 1;
}
/* Allocation concurrency is protected by the console semaphore */
static int speakup_allocate(struct vc_data *vc, gfp_t gfp_flags)
{
<------>int vc_num;
<------>vc_num = vc->vc_num;
<------>if (!speakup_console[vc_num]) {
<------><------>speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]),
<------><------><------><------><------><------> gfp_flags);
<------><------>if (!speakup_console[vc_num])
<------><------><------>return -ENOMEM;
<------><------>speakup_date(vc);
<------>} else if (!spk_parked) {
<------><------>speakup_date(vc);
<------>}
<------>return 0;
}
static void speakup_deallocate(struct vc_data *vc)
{
<------>int vc_num;
<------>vc_num = vc->vc_num;
<------>kfree(speakup_console[vc_num]);
<------>speakup_console[vc_num] = NULL;
}
static u_char is_cursor;
static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
static int cursor_con;
static void reset_highlight_buffers(struct vc_data *);
static int read_all_key;
static int in_keyboard_notifier;
static void start_read_all_timer(struct vc_data *vc, int command);
enum {
<------>RA_NOTHING,
<------>RA_NEXT_SENT,
<------>RA_PREV_LINE,
<------>RA_NEXT_LINE,
<------>RA_PREV_SENT,
<------>RA_DOWN_ARROW,
<------>RA_TIMER,
<------>RA_FIND_NEXT_SENT,
<------>RA_FIND_PREV_SENT,
};
static void kbd_fakekey2(struct vc_data *vc, int command)
{
<------>del_timer(&cursor_timer);
<------>speakup_fake_down_arrow();
<------>start_read_all_timer(vc, command);
}
static void read_all_doc(struct vc_data *vc)
{
<------>if ((vc->vc_num != fg_console) || !synth || spk_shut_up)
<------><------>return;
<------>if (!synth_supports_indexing())
<------><------>return;
<------>if (cursor_track != read_all_mode)
<------><------>prev_cursor_track = cursor_track;
<------>cursor_track = read_all_mode;
<------>spk_reset_index_count(0);
<------>if (get_sentence_buf(vc, 0) == -1) {
<------><------>del_timer(&cursor_timer);
<------><------>if (!in_keyboard_notifier)
<------><------><------>speakup_fake_down_arrow();
<------><------>start_read_all_timer(vc, RA_DOWN_ARROW);
<------>} else {
<------><------>say_sentence_num(0, 0);
<------><------>synth_insert_next_index(0);
<------><------>start_read_all_timer(vc, RA_TIMER);
<------>}
}
static void stop_read_all(struct vc_data *vc)
{
<------>del_timer(&cursor_timer);
<------>cursor_track = prev_cursor_track;
<------>spk_shut_up &= 0xfe;
<------>spk_do_flush();
}
static void start_read_all_timer(struct vc_data *vc, int command)
{
<------>struct var_t *cursor_timeout;
<------>cursor_con = vc->vc_num;
<------>read_all_key = command;
<------>cursor_timeout = spk_get_var(CURSOR_TIME);
<------>mod_timer(&cursor_timer,
<------><------> jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
}
static void handle_cursor_read_all(struct vc_data *vc, int command)
{
<------>int indcount, sentcount, rv, sn;
<------>switch (command) {
<------>case RA_NEXT_SENT:
<------><------>/* Get Current Sentence */
<------><------>spk_get_index_count(&indcount, &sentcount);
<------><------>/*printk("%d %d ", indcount, sentcount); */
<------><------>spk_reset_index_count(sentcount + 1);
<------><------>if (indcount == 1) {
<------><------><------>if (!say_sentence_num(sentcount + 1, 0)) {
<------><------><------><------>kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
<------><------><------><------>return;
<------><------><------>}
<------><------><------>synth_insert_next_index(0);
<------><------>} else {
<------><------><------>sn = 0;
<------><------><------>if (!say_sentence_num(sentcount + 1, 1)) {
<------><------><------><------>sn = 1;
<------><------><------><------>spk_reset_index_count(sn);
<------><------><------>} else {
<------><------><------><------>synth_insert_next_index(0);
<------><------><------>}
<------><------><------>if (!say_sentence_num(sn, 0)) {
<------><------><------><------>kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
<------><------><------><------>return;
<------><------><------>}
<------><------><------>synth_insert_next_index(0);
<------><------>}
<------><------>start_read_all_timer(vc, RA_TIMER);
<------><------>break;
<------>case RA_PREV_SENT:
<------><------>break;
<------>case RA_NEXT_LINE:
<------><------>read_all_doc(vc);
<------><------>break;
<------>case RA_PREV_LINE:
<------><------>break;
<------>case RA_DOWN_ARROW:
<------><------>if (get_sentence_buf(vc, 0) == -1) {
<------><------><------>kbd_fakekey2(vc, RA_DOWN_ARROW);
<------><------>} else {
<------><------><------>say_sentence_num(0, 0);
<------><------><------>synth_insert_next_index(0);
<------><------><------>start_read_all_timer(vc, RA_TIMER);
<------><------>}
<------><------>break;
<------>case RA_FIND_NEXT_SENT:
<------><------>rv = get_sentence_buf(vc, 0);
<------><------>if (rv == -1)
<------><------><------>read_all_doc(vc);
<------><------>if (rv == 0) {
<------><------><------>kbd_fakekey2(vc, RA_FIND_NEXT_SENT);
<------><------>} else {
<------><------><------>say_sentence_num(1, 0);
<------><------><------>synth_insert_next_index(0);
<------><------><------>start_read_all_timer(vc, RA_TIMER);
<------><------>}
<------><------>break;
<------>case RA_FIND_PREV_SENT:
<------><------>break;
<------>case RA_TIMER:
<------><------>spk_get_index_count(&indcount, &sentcount);
<------><------>if (indcount < 2)
<------><------><------>kbd_fakekey2(vc, RA_DOWN_ARROW);
<------><------>else
<------><------><------>start_read_all_timer(vc, RA_TIMER);
<------><------>break;
<------>}
}
static int pre_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
{
<------>unsigned long flags;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>if (cursor_track == read_all_mode) {
<------><------>spk_parked &= 0xfe;
<------><------>if (!synth || up_flag || spk_shut_up) {
<------><------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------><------>return NOTIFY_STOP;
<------><------>}
<------><------>del_timer(&cursor_timer);
<------><------>spk_shut_up &= 0xfe;
<------><------>spk_do_flush();
<------><------>start_read_all_timer(vc, value + 1);
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return NOTIFY_STOP;
<------>}
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------>return NOTIFY_OK;
}
static void do_handle_cursor(struct vc_data *vc, u_char value, char up_flag)
{
<------>unsigned long flags;
<------>struct var_t *cursor_timeout;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>spk_parked &= 0xfe;
<------>if (!synth || up_flag || spk_shut_up || cursor_track == CT_Off) {
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>spk_shut_up &= 0xfe;
<------>if (spk_no_intr)
<------><------>spk_do_flush();
/* the key press flushes if !no_inter but we want to flush on cursor
* moves regardless of no_inter state
*/
<------>is_cursor = value + 1;
<------>old_cursor_pos = vc->vc_pos;
<------>old_cursor_x = vc->state.x;
<------>old_cursor_y = vc->state.y;
<------>speakup_console[vc->vc_num]->ht.cy = vc->state.y;
<------>cursor_con = vc->vc_num;
<------>if (cursor_track == CT_Highlight)
<------><------>reset_highlight_buffers(vc);
<------>cursor_timeout = spk_get_var(CURSOR_TIME);
<------>mod_timer(&cursor_timer,
<------><------> jiffies + msecs_to_jiffies(cursor_timeout->u.n.value));
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
static void update_color_buffer(struct vc_data *vc, const u16 *ic, int len)
{
<------>int i, bi, hi;
<------>int vc_num = vc->vc_num;
<------>bi = (vc->vc_attr & 0x70) >> 4;
<------>hi = speakup_console[vc_num]->ht.highsize[bi];
<------>i = 0;
<------>if (speakup_console[vc_num]->ht.highsize[bi] == 0) {
<------><------>speakup_console[vc_num]->ht.rpos[bi] = vc->vc_pos;
<------><------>speakup_console[vc_num]->ht.rx[bi] = vc->state.x;
<------><------>speakup_console[vc_num]->ht.ry[bi] = vc->state.y;
<------>}
<------>while ((hi < COLOR_BUFFER_SIZE) && (i < len)) {
<------><------>if (ic[i] > 32) {
<------><------><------>speakup_console[vc_num]->ht.highbuf[bi][hi] = ic[i];
<------><------><------>hi++;
<------><------>} else if ((ic[i] == 32) && (hi != 0)) {
<------><------><------>if (speakup_console[vc_num]->ht.highbuf[bi][hi - 1] !=
<------><------><------> 32) {
<------><------><------><------>speakup_console[vc_num]->ht.highbuf[bi][hi] =
<------><------><------><------> ic[i];
<------><------><------><------>hi++;
<------><------><------>}
<------><------>}
<------><------>i++;
<------>}
<------>speakup_console[vc_num]->ht.highsize[bi] = hi;
}
static void reset_highlight_buffers(struct vc_data *vc)
{
<------>int i;
<------>int vc_num = vc->vc_num;
<------>for (i = 0; i < 8; i++)
<------><------>speakup_console[vc_num]->ht.highsize[i] = 0;
}
static int count_highlight_color(struct vc_data *vc)
{
<------>int i, bg;
<------>int cc;
<------>int vc_num = vc->vc_num;
<------>u16 ch;
<------>u16 *start = (u16 *)vc->vc_origin;
<------>for (i = 0; i < 8; i++)
<------><------>speakup_console[vc_num]->ht.bgcount[i] = 0;
<------>for (i = 0; i < vc->vc_rows; i++) {
<------><------>u16 *end = start + vc->vc_cols * 2;
<------><------>u16 *ptr;
<------><------>for (ptr = start; ptr < end; ptr++) {
<------><------><------>ch = get_attributes(vc, ptr);
<------><------><------>bg = (ch & 0x70) >> 4;
<------><------><------>speakup_console[vc_num]->ht.bgcount[bg]++;
<------><------>}
<------><------>start += vc->vc_size_row;
<------>}
<------>cc = 0;
<------>for (i = 0; i < 8; i++)
<------><------>if (speakup_console[vc_num]->ht.bgcount[i] > 0)
<------><------><------>cc++;
<------>return cc;
}
static int get_highlight_color(struct vc_data *vc)
{
<------>int i, j;
<------>unsigned int cptr[8];
<------>int vc_num = vc->vc_num;
<------>for (i = 0; i < 8; i++)
<------><------>cptr[i] = i;
<------>for (i = 0; i < 7; i++)
<------><------>for (j = i + 1; j < 8; j++)
<------><------><------>if (speakup_console[vc_num]->ht.bgcount[cptr[i]] >
<------><------><------> speakup_console[vc_num]->ht.bgcount[cptr[j]])
<------><------><------><------>swap(cptr[i], cptr[j]);
<------>for (i = 0; i < 8; i++)
<------><------>if (speakup_console[vc_num]->ht.bgcount[cptr[i]] != 0)
<------><------><------>if (speakup_console[vc_num]->ht.highsize[cptr[i]] > 0)
<------><------><------><------>return cptr[i];
<------>return -1;
}
static int speak_highlight(struct vc_data *vc)
{
<------>int hc, d;
<------>int vc_num = vc->vc_num;
<------>if (count_highlight_color(vc) == 1)
<------><------>return 0;
<------>hc = get_highlight_color(vc);
<------>if (hc != -1) {
<------><------>d = vc->state.y - speakup_console[vc_num]->ht.cy;
<------><------>if ((d == 1) || (d == -1))
<------><------><------>if (speakup_console[vc_num]->ht.ry[hc] != vc->state.y)
<------><------><------><------>return 0;
<------><------>spk_parked |= 0x01;
<------><------>spk_do_flush();
<------><------>spkup_write(speakup_console[vc_num]->ht.highbuf[hc],
<------><------><------> speakup_console[vc_num]->ht.highsize[hc]);
<------><------>spk_pos = spk_cp = speakup_console[vc_num]->ht.rpos[hc];
<------><------>spk_x = spk_cx = speakup_console[vc_num]->ht.rx[hc];
<------><------>spk_y = spk_cy = speakup_console[vc_num]->ht.ry[hc];
<------><------>return 1;
<------>}
<------>return 0;
}
static void cursor_done(struct timer_list *unused)
{
<------>struct vc_data *vc = vc_cons[cursor_con].d;
<------>unsigned long flags;
<------>del_timer(&cursor_timer);
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>if (cursor_con != fg_console) {
<------><------>is_cursor = 0;
<------><------>goto out;
<------>}
<------>speakup_date(vc);
<------>if (win_enabled) {
<------><------>if (vc->state.x >= win_left && vc->state.x <= win_right &&
<------><------> vc->state.y >= win_top && vc->state.y <= win_bottom) {
<------><------><------>spk_keydown = 0;
<------><------><------>is_cursor = 0;
<------><------><------>goto out;
<------><------>}
<------>}
<------>if (cursor_track == read_all_mode) {
<------><------>handle_cursor_read_all(vc, read_all_key);
<------><------>goto out;
<------>}
<------>if (cursor_track == CT_Highlight) {
<------><------>if (speak_highlight(vc)) {
<------><------><------>spk_keydown = 0;
<------><------><------>is_cursor = 0;
<------><------><------>goto out;
<------><------>}
<------>}
<------>if (cursor_track == CT_Window)
<------><------>speakup_win_say(vc);
<------>else if (is_cursor == 1 || is_cursor == 4)
<------><------>say_line_from_to(vc, 0, vc->vc_cols, 0);
<------>else
<------><------>say_char(vc);
<------>spk_keydown = 0;
<------>is_cursor = 0;
out:
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
/* called by: vt_notifier_call() */
static void speakup_bs(struct vc_data *vc)
{
<------>unsigned long flags;
<------>if (!speakup_console[vc->vc_num])
<------><------>return;
<------>if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
<------><------>/* Speakup output, discard */
<------><------>return;
<------>if (!spk_parked)
<------><------>speakup_date(vc);
<------>if (spk_shut_up || !synth) {
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>if (vc->vc_num == fg_console && spk_keydown) {
<------><------>spk_keydown = 0;
<------><------>if (!is_cursor)
<------><------><------>say_char(vc);
<------>}
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
/* called by: vt_notifier_call() */
static void speakup_con_write(struct vc_data *vc, u16 *str, int len)
{
<------>unsigned long flags;
<------>if ((vc->vc_num != fg_console) || spk_shut_up || !synth)
<------><------>return;
<------>if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
<------><------>/* Speakup output, discard */
<------><------>return;
<------>if (spk_bell_pos && spk_keydown && (vc->state.x == spk_bell_pos - 1))
<------><------>bleep(3);
<------>if ((is_cursor) || (cursor_track == read_all_mode)) {
<------><------>if (cursor_track == CT_Highlight)
<------><------><------>update_color_buffer(vc, str, len);
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>if (win_enabled) {
<------><------>if (vc->state.x >= win_left && vc->state.x <= win_right &&
<------><------> vc->state.y >= win_top && vc->state.y <= win_bottom) {
<------><------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------><------>return;
<------><------>}
<------>}
<------>spkup_write(str, len);
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
static void speakup_con_update(struct vc_data *vc)
{
<------>unsigned long flags;
<------>if (!speakup_console[vc->vc_num] || spk_parked)
<------><------>return;
<------>if (!spin_trylock_irqsave(&speakup_info.spinlock, flags))
<------><------>/* Speakup output, discard */
<------><------>return;
<------>speakup_date(vc);
<------>if (vc->vc_mode == KD_GRAPHICS && !spk_paused && spk_str_pause[0]) {
<------><------>synth_printf("%s", spk_str_pause);
<------><------>spk_paused = true;
<------>}
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
static void do_handle_spec(struct vc_data *vc, u_char value, char up_flag)
{
<------>unsigned long flags;
<------>int on_off = 2;
<------>char *label;
<------>if (!synth || up_flag || spk_killed)
<------><------>return;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>spk_shut_up &= 0xfe;
<------>if (spk_no_intr)
<------><------>spk_do_flush();
<------>switch (value) {
<------>case KVAL(K_CAPS):
<------><------>label = spk_msg_get(MSG_KEYNAME_CAPSLOCK);
<------><------>on_off = vt_get_leds(fg_console, VC_CAPSLOCK);
<------><------>break;
<------>case KVAL(K_NUM):
<------><------>label = spk_msg_get(MSG_KEYNAME_NUMLOCK);
<------><------>on_off = vt_get_leds(fg_console, VC_NUMLOCK);
<------><------>break;
<------>case KVAL(K_HOLD):
<------><------>label = spk_msg_get(MSG_KEYNAME_SCROLLLOCK);
<------><------>on_off = vt_get_leds(fg_console, VC_SCROLLOCK);
<------><------>if (speakup_console[vc->vc_num])
<------><------><------>speakup_console[vc->vc_num]->tty_stopped = on_off;
<------><------>break;
<------>default:
<------><------>spk_parked &= 0xfe;
<------><------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------><------>return;
<------>}
<------>if (on_off < 2)
<------><------>synth_printf("%s %s\n",
<------><------><------> label, spk_msg_get(MSG_STATUS_START + on_off));
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
}
static int inc_dec_var(u_char value)
{
<------>struct st_var_header *p_header;
<------>struct var_t *var_data;
<------>char num_buf[32];
<------>char *cp = num_buf;
<------>char *pn;
<------>int var_id = (int)value - VAR_START;
<------>int how = (var_id & 1) ? E_INC : E_DEC;
<------>var_id = var_id / 2 + FIRST_SET_VAR;
<------>p_header = spk_get_var_header(var_id);
<------>if (!p_header)
<------><------>return -1;
<------>if (p_header->var_type != VAR_NUM)
<------><------>return -1;
<------>var_data = p_header->data;
<------>if (spk_set_num_var(1, p_header, how) != 0)
<------><------>return -1;
<------>if (!spk_close_press) {
<------><------>for (pn = p_header->name; *pn; pn++) {
<------><------><------>if (*pn == '_')
<------><------><------><------>*cp = SPACE;
<------><------><------>else
<------><------><------><------>*cp++ = *pn;
<------><------>}
<------>}
<------>snprintf(cp, sizeof(num_buf) - (cp - num_buf), " %d ",
<------><------> var_data->u.n.value);
<------>synth_printf("%s", num_buf);
<------>return 0;
}
static void speakup_win_set(struct vc_data *vc)
{
<------>char info[40];
<------>if (win_start > 1) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_WINDOW_ALREADY_SET));
<------><------>return;
<------>}
<------>if (spk_x < win_left || spk_y < win_top) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_END_BEFORE_START));
<------><------>return;
<------>}
<------>if (win_start && spk_x == win_left && spk_y == win_top) {
<------><------>win_left = 0;
<------><------>win_right = vc->vc_cols - 1;
<------><------>win_bottom = spk_y;
<------><------>snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_LINE),
<------><------><------> (int)win_top + 1);
<------>} else {
<------><------>if (!win_start) {
<------><------><------>win_top = spk_y;
<------><------><------>win_left = spk_x;
<------><------>} else {
<------><------><------>win_bottom = spk_y;
<------><------><------>win_right = spk_x;
<------><------>}
<------><------>snprintf(info, sizeof(info), spk_msg_get(MSG_WINDOW_BOUNDARY),
<------><------><------> (win_start) ?
<------><------><------><------>spk_msg_get(MSG_END) : spk_msg_get(MSG_START),
<------><------><------> (int)spk_y + 1, (int)spk_x + 1);
<------>}
<------>synth_printf("%s\n", info);
<------>win_start++;
}
static void speakup_win_clear(struct vc_data *vc)
{
<------>win_top = 0;
<------>win_bottom = 0;
<------>win_left = 0;
<------>win_right = 0;
<------>win_start = 0;
<------>synth_printf("%s\n", spk_msg_get(MSG_WINDOW_CLEARED));
}
static void speakup_win_enable(struct vc_data *vc)
{
<------>if (win_start < 2) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_NO_WINDOW));
<------><------>return;
<------>}
<------>win_enabled ^= 1;
<------>if (win_enabled)
<------><------>synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCED));
<------>else
<------><------>synth_printf("%s\n", spk_msg_get(MSG_WINDOW_SILENCE_DISABLED));
}
static void speakup_bits(struct vc_data *vc)
{
<------>int val = this_speakup_key - (FIRST_EDIT_BITS - 1);
<------>if (spk_special_handler || val < 1 || val > 6) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_ERROR));
<------><------>return;
<------>}
<------>pb_edit = &spk_punc_info[val];
<------>synth_printf(spk_msg_get(MSG_EDIT_PROMPT), pb_edit->name);
<------>spk_special_handler = edit_bits;
}
static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key)
{
<------>static u_char goto_buf[8];
<------>static int num;
<------>int maxlen;
<------>char *cp;
<------>u16 wch;
<------>if (type == KT_SPKUP && ch == SPEAKUP_GOTO)
<------><------>goto do_goto;
<------>if (type == KT_LATIN && ch == '\n')
<------><------>goto do_goto;
<------>if (type != 0)
<------><------>goto oops;
<------>if (ch == 8) {
<------><------>u16 wch;
<------><------>if (num == 0)
<------><------><------>return -1;
<------><------>wch = goto_buf[--num];
<------><------>goto_buf[num] = '\0';
<------><------>spkup_write(&wch, 1);
<------><------>return 1;
<------>}
<------>if (ch < '+' || ch > 'y')
<------><------>goto oops;
<------>wch = ch;
<------>goto_buf[num++] = ch;
<------>goto_buf[num] = '\0';
<------>spkup_write(&wch, 1);
<------>maxlen = (*goto_buf >= '0') ? 3 : 4;
<------>if ((ch == '+' || ch == '-') && num == 1)
<------><------>return 1;
<------>if (ch >= '0' && ch <= '9' && num < maxlen)
<------><------>return 1;
<------>if (num < maxlen - 1 || num > maxlen)
<------><------>goto oops;
<------>if (ch < 'x' || ch > 'y') {
oops:
<------><------>if (!spk_killed)
<------><------><------>synth_printf(" %s\n", spk_msg_get(MSG_GOTO_CANCELED));
<------><------>goto_buf[num = 0] = '\0';
<------><------>spk_special_handler = NULL;
<------><------>return 1;
<------>}
<------>/* Do not replace with kstrtoul: here we need cp to be updated */
<------>goto_pos = simple_strtoul(goto_buf, &cp, 10);
<------>if (*cp == 'x') {
<------><------>if (*goto_buf < '0')
<------><------><------>goto_pos += spk_x;
<------><------>else if (goto_pos > 0)
<------><------><------>goto_pos--;
<------><------>if (goto_pos >= vc->vc_cols)
<------><------><------>goto_pos = vc->vc_cols - 1;
<------><------>goto_x = 1;
<------>} else {
<------><------>if (*goto_buf < '0')
<------><------><------>goto_pos += spk_y;
<------><------>else if (goto_pos > 0)
<------><------><------>goto_pos--;
<------><------>if (goto_pos >= vc->vc_rows)
<------><------><------>goto_pos = vc->vc_rows - 1;
<------><------>goto_x = 0;
<------>}
<------>goto_buf[num = 0] = '\0';
do_goto:
<------>spk_special_handler = NULL;
<------>spk_parked |= 0x01;
<------>if (goto_x) {
<------><------>spk_pos -= spk_x * 2;
<------><------>spk_x = goto_pos;
<------><------>spk_pos += goto_pos * 2;
<------><------>say_word(vc);
<------>} else {
<------><------>spk_y = goto_pos;
<------><------>spk_pos = vc->vc_origin + (goto_pos * vc->vc_size_row);
<------><------>say_line(vc);
<------>}
<------>return 1;
}
static void speakup_goto(struct vc_data *vc)
{
<------>if (spk_special_handler) {
<------><------>synth_printf("%s\n", spk_msg_get(MSG_ERROR));
<------><------>return;
<------>}
<------>synth_printf("%s\n", spk_msg_get(MSG_GOTO));
<------>spk_special_handler = handle_goto;
}
static void speakup_help(struct vc_data *vc)
{
<------>spk_handle_help(vc, KT_SPKUP, SPEAKUP_HELP, 0);
}
static void do_nothing(struct vc_data *vc)
{
<------>return; /* flush done in do_spkup */
}
static u_char key_speakup, spk_key_locked;
static void speakup_lock(struct vc_data *vc)
{
<------>if (!spk_key_locked) {
<------><------>spk_key_locked = 16;
<------><------>key_speakup = 16;
<------>} else {
<------><------>spk_key_locked = 0;
<------><------>key_speakup = 0;
<------>}
}
typedef void (*spkup_hand) (struct vc_data *);
static spkup_hand spkup_handler[] = {
<------>/* must be ordered same as defines in speakup.h */
<------>do_nothing, speakup_goto, speech_kill, speakup_shut_up,
<------>speakup_cut, speakup_paste, say_first_char, say_last_char,
<------>say_char, say_prev_char, say_next_char,
<------>say_word, say_prev_word, say_next_word,
<------>say_line, say_prev_line, say_next_line,
<------>top_edge, bottom_edge, left_edge, right_edge,
<------>spell_word, spell_word, say_screen,
<------>say_position, say_attributes,
<------>speakup_off, speakup_parked, say_line, /* this is for indent */
<------>say_from_top, say_to_bottom,
<------>say_from_left, say_to_right,
<------>say_char_num, speakup_bits, speakup_bits, say_phonetic_char,
<------>speakup_bits, speakup_bits, speakup_bits,
<------>speakup_win_set, speakup_win_clear, speakup_win_enable, speakup_win_say,
<------>speakup_lock, speakup_help, toggle_cursoring, read_all_doc, NULL
};
static void do_spkup(struct vc_data *vc, u_char value)
{
<------>if (spk_killed && value != SPEECH_KILL)
<------><------>return;
<------>spk_keydown = 0;
<------>spk_lastkey = 0;
<------>spk_shut_up &= 0xfe;
<------>this_speakup_key = value;
<------>if (value < SPKUP_MAX_FUNC && spkup_handler[value]) {
<------><------>spk_do_flush();
<------><------>(*spkup_handler[value]) (vc);
<------>} else {
<------><------>if (inc_dec_var(value) < 0)
<------><------><------>bleep(9);
<------>}
}
static const char *pad_chars = "0123456789+-*/\015,.?()";
static int
speakup_key(struct vc_data *vc, int shift_state, int keycode, u_short keysym,
<------> int up_flag)
{
<------>unsigned long flags;
<------>int kh;
<------>u_char *key_info;
<------>u_char type = KTYP(keysym), value = KVAL(keysym), new_key = 0;
<------>u_char shift_info, offset;
<------>int ret = 0;
<------>if (!synth)
<------><------>return 0;
<------>spin_lock_irqsave(&speakup_info.spinlock, flags);
<------>tty = vc->port.tty;
<------>if (type >= 0xf0)
<------><------>type -= 0xf0;
<------>if (type == KT_PAD &&
<------> (vt_get_leds(fg_console, VC_NUMLOCK))) {
<------><------>if (up_flag) {
<------><------><------>spk_keydown = 0;
<------><------><------>goto out;
<------><------>}
<------><------>value = pad_chars[value];
<------><------>spk_lastkey = value;
<------><------>spk_keydown++;
<------><------>spk_parked &= 0xfe;
<------><------>goto no_map;
<------>}
<------>if (keycode >= MAX_KEY)
<------><------>goto no_map;
<------>key_info = spk_our_keys[keycode];
<------>if (!key_info)
<------><------>goto no_map;
<------>/* Check valid read all mode keys */
<------>if ((cursor_track == read_all_mode) && (!up_flag)) {
<------><------>switch (value) {
<------><------>case KVAL(K_DOWN):
<------><------>case KVAL(K_UP):
<------><------>case KVAL(K_LEFT):
<------><------>case KVAL(K_RIGHT):
<------><------>case KVAL(K_PGUP):
<------><------>case KVAL(K_PGDN):
<------><------><------>break;
<------><------>default:
<------><------><------>stop_read_all(vc);
<------><------><------>break;
<------><------>}
<------>}
<------>shift_info = (shift_state & 0x0f) + key_speakup;
<------>offset = spk_shift_table[shift_info];
<------>if (offset) {
<------><------>new_key = key_info[offset];
<------><------>if (new_key) {
<------><------><------>ret = 1;
<------><------><------>if (new_key == SPK_KEY) {
<------><------><------><------>if (!spk_key_locked)
<------><------><------><------><------>key_speakup = (up_flag) ? 0 : 16;
<------><------><------><------>if (up_flag || spk_killed)
<------><------><------><------><------>goto out;
<------><------><------><------>spk_shut_up &= 0xfe;
<------><------><------><------>spk_do_flush();
<------><------><------><------>goto out;
<------><------><------>}
<------><------><------>if (up_flag)
<------><------><------><------>goto out;
<------><------><------>if (last_keycode == keycode &&
<------><------><------> time_after(last_spk_jiffy + MAX_DELAY, jiffies)) {
<------><------><------><------>spk_close_press = 1;
<------><------><------><------>offset = spk_shift_table[shift_info + 32];
<------><------><------><------>/* double press? */
<------><------><------><------>if (offset && key_info[offset])
<------><------><------><------><------>new_key = key_info[offset];
<------><------><------>}
<------><------><------>last_keycode = keycode;
<------><------><------>last_spk_jiffy = jiffies;
<------><------><------>type = KT_SPKUP;
<------><------><------>value = new_key;
<------><------>}
<------>}
no_map:
<------>if (type == KT_SPKUP && !spk_special_handler) {
<------><------>do_spkup(vc, new_key);
<------><------>spk_close_press = 0;
<------><------>ret = 1;
<------><------>goto out;
<------>}
<------>if (up_flag || spk_killed || type == KT_SHIFT)
<------><------>goto out;
<------>spk_shut_up &= 0xfe;
<------>kh = (value == KVAL(K_DOWN)) ||
<------> (value == KVAL(K_UP)) ||
<------> (value == KVAL(K_LEFT)) ||
<------> (value == KVAL(K_RIGHT));
<------>if ((cursor_track != read_all_mode) || !kh)
<------><------>if (!spk_no_intr)
<------><------><------>spk_do_flush();
<------>if (spk_special_handler) {
<------><------>if (type == KT_SPEC && value == 1) {
<------><------><------>value = '\n';
<------><------><------>type = KT_LATIN;
<------><------>} else if (type == KT_LETTER) {
<------><------><------>type = KT_LATIN;
<------><------>} else if (value == 0x7f) {
<------><------><------>value = 8; /* make del = backspace */
<------><------>}
<------><------>ret = (*spk_special_handler) (vc, type, value, keycode);
<------><------>spk_close_press = 0;
<------><------>if (ret < 0)
<------><------><------>bleep(9);
<------><------>goto out;
<------>}
<------>last_keycode = 0;
out:
<------>spin_unlock_irqrestore(&speakup_info.spinlock, flags);
<------>return ret;
}
static int keyboard_notifier_call(struct notifier_block *nb,
<------><------><------><------> unsigned long code, void *_param)
{
<------>struct keyboard_notifier_param *param = _param;
<------>struct vc_data *vc = param->vc;
<------>int up = !param->down;
<------>int ret = NOTIFY_OK;
<------>static int keycode; /* to hold the current keycode */
<------>in_keyboard_notifier = 1;
<------>if (vc->vc_mode == KD_GRAPHICS)
<------><------>goto out;
<------>/*
<------> * First, determine whether we are handling a fake keypress on
<------> * the current processor. If we are, then return NOTIFY_OK,
<------> * to pass the keystroke up the chain. This prevents us from
<------> * trying to take the Speakup lock while it is held by the
<------> * processor on which the simulated keystroke was generated.
<------> * Also, the simulated keystrokes should be ignored by Speakup.
<------> */
<------>if (speakup_fake_key_pressed())
<------><------>goto out;
<------>switch (code) {
<------>case KBD_KEYCODE:
<------><------>/* speakup requires keycode and keysym currently */
<------><------>keycode = param->value;
<------><------>break;
<------>case KBD_UNBOUND_KEYCODE:
<------><------>/* not used yet */
<------><------>break;
<------>case KBD_UNICODE:
<------><------>/* not used yet */
<------><------>break;
<------>case KBD_KEYSYM:
<------><------>if (speakup_key(vc, param->shift, keycode, param->value, up))
<------><------><------>ret = NOTIFY_STOP;
<------><------>else if (KTYP(param->value) == KT_CUR)
<------><------><------>ret = pre_handle_cursor(vc, KVAL(param->value), up);
<------><------>break;
<------>case KBD_POST_KEYSYM:{
<------><------><------>unsigned char type = KTYP(param->value) - 0xf0;
<------><------><------>unsigned char val = KVAL(param->value);
<------><------><------>switch (type) {
<------><------><------>case KT_SHIFT:
<------><------><------><------>do_handle_shift(vc, val, up);
<------><------><------><------>break;
<------><------><------>case KT_LATIN:
<------><------><------>case KT_LETTER:
<------><------><------><------>do_handle_latin(vc, val, up);
<------><------><------><------>break;
<------><------><------>case KT_CUR:
<------><------><------><------>do_handle_cursor(vc, val, up);
<------><------><------><------>break;
<------><------><------>case KT_SPEC:
<------><------><------><------>do_handle_spec(vc, val, up);
<------><------><------><------>break;
<------><------><------>}
<------><------><------>break;
<------><------>}
<------>}
out:
<------>in_keyboard_notifier = 0;
<------>return ret;
}
static int vt_notifier_call(struct notifier_block *nb,
<------><------><------> unsigned long code, void *_param)
{
<------>struct vt_notifier_param *param = _param;
<------>struct vc_data *vc = param->vc;
<------>switch (code) {
<------>case VT_ALLOCATE:
<------><------>if (vc->vc_mode == KD_TEXT)
<------><------><------>speakup_allocate(vc, GFP_ATOMIC);
<------><------>break;
<------>case VT_DEALLOCATE:
<------><------>speakup_deallocate(vc);
<------><------>break;
<------>case VT_WRITE:
<------><------>if (param->c == '\b') {
<------><------><------>speakup_bs(vc);
<------><------>} else {
<------><------><------>u16 d = param->c;
<------><------><------>speakup_con_write(vc, &d, 1);
<------><------>}
<------><------>break;
<------>case VT_UPDATE:
<------><------>speakup_con_update(vc);
<------><------>break;
<------>}
<------>return NOTIFY_OK;
}
/* called by: module_exit() */
static void __exit speakup_exit(void)
{
<------>int i;
<------>unregister_keyboard_notifier(&keyboard_notifier_block);
<------>unregister_vt_notifier(&vt_notifier_block);
<------>speakup_unregister_devsynth();
<------>speakup_cancel_selection();
<------>speakup_cancel_paste();
<------>del_timer_sync(&cursor_timer);
<------>kthread_stop(speakup_task);
<------>speakup_task = NULL;
<------>mutex_lock(&spk_mutex);
<------>synth_release();
<------>mutex_unlock(&spk_mutex);
<------>spk_ttyio_unregister_ldisc();
<------>speakup_kobj_exit();
<------>for (i = 0; i < MAX_NR_CONSOLES; i++)
<------><------>kfree(speakup_console[i]);
<------>speakup_remove_virtual_keyboard();
<------>for (i = 0; i < MAXVARS; i++)
<------><------>speakup_unregister_var(i);
<------>for (i = 0; i < 256; i++) {
<------><------>if (spk_characters[i] != spk_default_chars[i])
<------><------><------>kfree(spk_characters[i]);
<------>}
<------>spk_free_user_msgs();
}
/* call by: module_init() */
static int __init speakup_init(void)
{
<------>int i;
<------>long err = 0;
<------>struct vc_data *vc = vc_cons[fg_console].d;
<------>struct var_t *var;
<------>/* These first few initializations cannot fail. */
<------>spk_initialize_msgs(); /* Initialize arrays for i18n. */
<------>spk_reset_default_chars();
<------>spk_reset_default_chartab();
<------>spk_strlwr(synth_name);
<------>spk_vars[0].u.n.high = vc->vc_cols;
<------>for (var = spk_vars; var->var_id != MAXVARS; var++)
<------><------>speakup_register_var(var);
<------>for (var = synth_time_vars;
<------> (var->var_id >= 0) && (var->var_id < MAXVARS); var++)
<------><------>speakup_register_var(var);
<------>for (i = 1; spk_punc_info[i].mask != 0; i++)
<------><------>spk_set_mask_bits(NULL, i, 2);
<------>spk_set_key_info(spk_key_defaults, spk_key_buf);
<------>/* From here on out, initializations can fail. */
<------>err = speakup_add_virtual_keyboard();
<------>if (err)
<------><------>goto error_virtkeyboard;
<------>for (i = 0; i < MAX_NR_CONSOLES; i++)
<------><------>if (vc_cons[i].d) {
<------><------><------>err = speakup_allocate(vc_cons[i].d, GFP_KERNEL);
<------><------><------>if (err)
<------><------><------><------>goto error_kobjects;
<------><------>}
<------>if (spk_quiet_boot)
<------><------>spk_shut_up |= 0x01;
<------>err = speakup_kobj_init();
<------>if (err)
<------><------>goto error_kobjects;
<------>spk_ttyio_register_ldisc();
<------>synth_init(synth_name);
<------>speakup_register_devsynth();
<------>/*
<------> * register_devsynth might fail, but this error is not fatal.
<------> * /dev/synth is an extra feature; the rest of Speakup
<------> * will work fine without it.
<------> */
<------>err = register_keyboard_notifier(&keyboard_notifier_block);
<------>if (err)
<------><------>goto error_kbdnotifier;
<------>err = register_vt_notifier(&vt_notifier_block);
<------>if (err)
<------><------>goto error_vtnotifier;
<------>speakup_task = kthread_create(speakup_thread, NULL, "speakup");
<------>if (IS_ERR(speakup_task)) {
<------><------>err = PTR_ERR(speakup_task);
<------><------>goto error_task;
<------>}
<------>set_user_nice(speakup_task, 10);
<------>wake_up_process(speakup_task);
<------>pr_info("speakup %s: initialized\n", SPEAKUP_VERSION);
<------>pr_info("synth name on entry is: %s\n", synth_name);
<------>goto out;
error_task:
<------>unregister_vt_notifier(&vt_notifier_block);
error_vtnotifier:
<------>unregister_keyboard_notifier(&keyboard_notifier_block);
<------>del_timer(&cursor_timer);
error_kbdnotifier:
<------>speakup_unregister_devsynth();
<------>mutex_lock(&spk_mutex);
<------>synth_release();
<------>mutex_unlock(&spk_mutex);
<------>speakup_kobj_exit();
error_kobjects:
<------>for (i = 0; i < MAX_NR_CONSOLES; i++)
<------><------>kfree(speakup_console[i]);
<------>speakup_remove_virtual_keyboard();
error_virtkeyboard:
<------>for (i = 0; i < MAXVARS; i++)
<------><------>speakup_unregister_var(i);
<------>for (i = 0; i < 256; i++) {
<------><------>if (spk_characters[i] != spk_default_chars[i])
<------><------><------>kfree(spk_characters[i]);
<------>}
<------>spk_free_user_msgs();
out:
<------>return err;
}
module_init(speakup_init);
module_exit(speakup_exit);