diff --git a/debian/changelog b/debian/changelog index e256455f9..841ae5290 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ linux-2.6 (2.6.31-1~experimental.3) UNRELEASED; urgency=low [ Ben Hutchings ] * Include aufs2, marked as staging (Closes: #541828) + * Include speakup modules under staging -- Ben Hutchings Tue, 13 Oct 2009 02:18:40 +0100 diff --git a/debian/config/kernelarch-x86/config b/debian/config/kernelarch-x86/config index 337891cb7..7d58cf7ae 100644 --- a/debian/config/kernelarch-x86/config +++ b/debian/config/kernelarch-x86/config @@ -389,6 +389,25 @@ CONFIG_RTL8187SE=m ## # CONFIG_SLICOSS is not set +## +## file: drivers/staging/speakup/Kconfig +## +CONFIG_SPEAKUP_SYNTH_ACNTSA=m +CONFIG_SPEAKUP_SYNTH_ACNTPC=m +CONFIG_SPEAKUP_SYNTH_APOLLO=m +CONFIG_SPEAKUP_SYNTH_AUDPTR=m +CONFIG_SPEAKUP_SYNTH_BNS=m +CONFIG_SPEAKUP_SYNTH_DECTLK=m +CONFIG_SPEAKUP_SYNTH_DECEXT=m +CONFIG_SPEAKUP_SYNTH_DTLK=m +CONFIG_SPEAKUP_SYNTH_KEYPC=m +CONFIG_SPEAKUP_SYNTH_LTLK=m +CONFIG_SPEAKUP_SYNTH_SOFT=m +CONFIG_SPEAKUP_SYNTH_SPKOUT=m +CONFIG_SPEAKUP_SYNTH_TXPRT=m +CONFIG_SPEAKUP_SYNTH_DUMMY=m +CONFIG_SPEAKUP=m + ## ## file: drivers/staging/stlc45xx/Kconfig ## diff --git a/debian/patches/features/all/speakup/speakup-add.patch b/debian/patches/features/all/speakup/speakup-add.patch new file mode 100644 index 000000000..2552d34e7 --- /dev/null +++ b/debian/patches/features/all/speakup/speakup-add.patch @@ -0,0 +1,10231 @@ +--- a/drivers/staging/speakup/allmodule.mk 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/allmodule.mk 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,15 @@ ++CONFIG_SPEAKUP_SYNTH_ACNTSA=m ++CONFIG_SPEAKUP_SYNTH_ACNTPC=m ++CONFIG_SPEAKUP_SYNTH_APOLLO=m ++CONFIG_SPEAKUP_SYNTH_AUDPTR=m ++CONFIG_SPEAKUP_SYNTH_BNS=m ++CONFIG_SPEAKUP_SYNTH_DECTLK=m ++CONFIG_SPEAKUP_SYNTH_DECEXT=m ++CONFIG_SPEAKUP_SYNTH_DTLK=m ++CONFIG_SPEAKUP_SYNTH_KEYPC=m ++CONFIG_SPEAKUP_SYNTH_LTLK=m ++CONFIG_SPEAKUP_SYNTH_SOFT=m ++CONFIG_SPEAKUP_SYNTH_SPKOUT=m ++CONFIG_SPEAKUP_SYNTH_TXPRT=m ++CONFIG_SPEAKUP_SYNTH_DUMMY=m ++CONFIG_SPEAKUP=m +--- a/drivers/staging/speakup/buffers.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/buffers.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,124 @@ ++#include ++#include ++#include /* for in_atomic */ ++#include ++#include ++ ++#include "speakup.h" ++#include "spk_priv.h" ++ ++#define synthBufferSize 8192 /* currently 8K bytes */ ++ ++static u_char synth_buffer[synthBufferSize]; /* guess what this is for! */ ++static u_char *buff_in = synth_buffer; ++static u_char *buff_out = synth_buffer; ++static u_char *buffer_end = synth_buffer+synthBufferSize-1; ++ ++/* These try to throttle applications by stopping the TTYs ++ * Note: we need to make sure that we will restart them eventually, which is ++ * usually not possible to do from the notifiers. ++ * ++ * So we only stop when we know alive == 1 (else we discard the data anyway), ++ * and the alive synth will eventually call start_ttys from the thread context. ++ */ ++void speakup_start_ttys(void) ++{ ++ int i; ++ ++ BUG_ON(in_atomic()); ++ lock_kernel(); ++ for (i = 0; i < MAX_NR_CONSOLES; i++) { ++ if (speakup_console[i] && speakup_console[i]->tty_stopped) ++ continue; ++ if ((vc_cons[i].d != NULL) && (vc_cons[i].d->vc_tty != NULL)) ++ start_tty(vc_cons[i].d->vc_tty); ++ } ++ unlock_kernel(); ++} ++EXPORT_SYMBOL_GPL(speakup_start_ttys); ++ ++static void speakup_stop_ttys(void) ++{ ++ int i; ++ ++ if (!in_atomic()) ++ lock_kernel(); ++ else if (!kernel_locked()) { ++ /* BKL is not held and we are in a critical section, too bad, ++ * let the buffer continue to fill up. ++ * ++ * This only happens with kernel messages and keyboard echo, so ++ * that shouldn't be so much a concern. ++ */ ++ return; ++ } ++ for (i = 0; i < MAX_NR_CONSOLES; i++) ++ if ((vc_cons[i].d != NULL) && (vc_cons[i].d->vc_tty != NULL)) ++ stop_tty(vc_cons[i].d->vc_tty); ++ if (!in_atomic()) ++ unlock_kernel(); ++ return; ++} ++ ++static int synth_buffer_free(void) ++{ ++ int bytesFree; ++ ++ if (buff_in >= buff_out) ++ bytesFree = synthBufferSize - (buff_in - buff_out); ++ else ++ bytesFree = buff_out - buff_in; ++ return bytesFree; ++} ++ ++int synth_buffer_empty(void) ++{ ++ return (buff_in == buff_out); ++} ++EXPORT_SYMBOL_GPL(synth_buffer_empty); ++ ++void synth_buffer_add(char ch) ++{ ++ if (!synth->alive) { ++ /* This makes sure that we won't stop TTYs if there is no synth ++ * to restart them */ ++ return; ++ } ++ if (synth_buffer_free() <= 100) { ++ synth_start(); ++ speakup_stop_ttys(); ++ } ++ if (synth_buffer_free() <= 1) ++ return; ++ *buff_in++ = ch; ++ if (buff_in > buffer_end) ++ buff_in = synth_buffer; ++} ++ ++char synth_buffer_getc(void) ++{ ++ char ch; ++ ++ if (buff_out == buff_in) ++ return 0; ++ ch = *buff_out++; ++ if (buff_out > buffer_end) ++ buff_out = synth_buffer; ++ return ch; ++} ++EXPORT_SYMBOL_GPL(synth_buffer_getc); ++ ++char synth_buffer_peek(void) ++{ ++ if (buff_out == buff_in) ++ return 0; ++ return *buff_out; ++} ++EXPORT_SYMBOL_GPL(synth_buffer_peek); ++ ++void synth_buffer_clear(void) ++{ ++ buff_in = buff_out = synth_buffer; ++ return; ++} ++EXPORT_SYMBOL_GPL(synth_buffer_clear); +--- a/drivers/staging/speakup/devsynth.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/devsynth.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,92 @@ ++#include ++#include /* for misc_register, and SYNTH_MINOR */ ++#include ++#include ++ ++#include "speakup.h" ++#include "spk_priv.h" ++ ++#ifndef SYNTH_MINOR ++#define SYNTH_MINOR 25 ++#endif ++ ++static int misc_registered; ++static int dev_opened; ++ ++static ssize_t speakup_file_write(struct file *fp, const char *buffer, ++ size_t nbytes, loff_t *ppos) ++{ ++ size_t count = nbytes; ++ const char *ptr = buffer; ++ int bytes; ++ unsigned long flags; ++ u_char buf[256]; ++ if (synth == NULL) ++ return -ENODEV; ++ while (count > 0) { ++ bytes = min_t(size_t, count, sizeof(buf)); ++ if (copy_from_user(buf, ptr, bytes)) ++ return -EFAULT; ++ count -= bytes; ++ ptr += bytes; ++ spk_lock(flags); ++ synth_write(buf, bytes); ++ spk_unlock(flags); ++ } ++ return (ssize_t) nbytes; ++} ++ ++static ssize_t speakup_file_read(struct file *fp, char *buf, size_t nbytes, loff_t *ppos) ++{ ++ return 0; ++} ++ ++static int speakup_file_open(struct inode *ip, struct file *fp) ++{ ++ if (synth == NULL) ++ return -ENODEV; ++ if (xchg(&dev_opened, 1)) ++ return -EBUSY; ++ return 0; ++} ++ ++static int speakup_file_release(struct inode *ip, struct file *fp) ++{ ++ dev_opened = 0; ++ return 0; ++} ++ ++static struct file_operations synth_fops = { ++ .read = speakup_file_read, ++ .write = speakup_file_write, ++ .open = speakup_file_open, ++ .release = speakup_file_release, ++}; ++ ++static struct miscdevice synth_device = { ++ .minor = SYNTH_MINOR, ++ .name = "synth", ++ .fops = &synth_fops, ++}; ++ ++void speakup_register_devsynth(void) ++{ ++ if (misc_registered != 0) ++ return; ++/* zero it so if register fails, deregister will not ref invalid ptrs */ ++ if (misc_register(&synth_device)) ++ pr_warn("Couldn't initialize miscdevice /dev/synth.\n"); ++ else { ++ pr_info("initialized device: /dev/synth, node (MAJOR %d, MINOR %d)\n", MISC_MAJOR, SYNTH_MINOR); ++ misc_registered = 1; ++ } ++} ++ ++void speakup_unregister_devsynth(void) ++{ ++ if (!misc_registered) ++ return; ++ pr_info("speakup: unregistering synth device /dev/synth\n"); ++ misc_deregister(&synth_device); ++ misc_registered = 0; ++} +--- a/drivers/staging/speakup/i18n.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/i18n.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,621 @@ ++/* Internationalization implementation. Includes definitions of English ++ * string arrays, and the i18n pointer. */ ++ ++#include ++#include ++#include ++#include "speakup.h" ++#include "spk_priv.h" ++ ++static char *speakup_msgs[MSG_LAST_INDEX]; ++static char *speakup_default_msgs [MSG_LAST_INDEX] = { ++ [MSG_BLANK] = "blank", ++ [MSG_IAM_ALIVE] = "I'm aLive!", ++ [MSG_YOU_KILLED_SPEAKUP] = "You killed speakup!", ++ [MSG_HEY_THATS_BETTER] = "hey. That's better!", ++ [MSG_YOU_TURNED_ME_OFF] = "You turned me off!", ++ [MSG_PARKED] = "parked!", ++ [MSG_UNPARKED] = "unparked!", ++ [MSG_MARK] = "mark", ++ [MSG_CUT] = "cut", ++ [MSG_MARK_CLEARED] = "mark, cleared", ++ [MSG_PASTE] = "paste", ++ [MSG_BRIGHT] = "bright", ++ [MSG_ON_BLINKING] = "on blinking", ++ [MSG_OFF] = "off", ++ [MSG_ON] = "on", ++ [MSG_NO_WINDOW] = "no window", ++ [MSG_CURSORING_OFF] = "cursoring off", ++ [MSG_CURSORING_ON] = "cursoring on", ++ [MSG_HIGHLIGHT_TRACKING] = "highlight tracking", ++ [MSG_READ_WINDOW] = "read windo", ++ [MSG_READ_ALL] = "read all", ++ [MSG_EDIT_DONE] = "edit done", ++ [MSG_WINDOW_ALREADY_SET] = "window already set, clear then reset", ++ [MSG_END_BEFORE_START] = "error end before start", ++ [MSG_WINDOW_CLEARED] = "window cleared", ++ [MSG_WINDOW_SILENCED] = "window silenced", ++ [MSG_WINDOW_SILENCE_DISABLED] = "window silence disabled", ++ [MSG_ERROR] = "error", ++ [MSG_GOTO_CANCELED] = "goto canceled", ++ [MSG_GOTO] = "go to?", ++ [MSG_LEAVING_HELP] = "leaving help", ++ [MSG_IS_UNASSIGNED] = "is unassigned", ++ [MSG_HELP_INFO] = "press space to leav help, cursor up or down to scroll, or a letter to go to commands in list", ++ [MSG_EDGE_TOP] = "top,", ++ [MSG_EDGE_BOTTOM] = "bottom,", ++ [MSG_EDGE_LEFT] = "left,", ++ [MSG_EDGE_RIGHT] = "right,", ++ [MSG_NUMBER] = "number", ++ [MSG_SPACE] = "space", ++ [MSG_START] = "start", ++ [MSG_END] = "end", ++ [MSG_CTRL] = "control-", ++ [MSG_DISJUNCTION] = "or", ++ ++/* Messages with embedded format specifiers. */ ++ [MSG_POS_INFO] = "line %ld, col %ld, t t y %d", ++ [MSG_CHAR_INFO] = "hex %02x, decimal %d", ++ [MSG_REPEAT_DESC] = "times %d .", ++ [MSG_REPEAT_DESC2] = "repeated %d .", ++ [MSG_WINDOW_LINE] = "window is line %d", ++ [MSG_WINDOW_BOUNDARY] = "%s at line %d, column %d", ++ [MSG_EDIT_PROMPT] = "edit %s, press space when done", ++ [MSG_NO_COMMAND] = "no commands for %c", ++ [MSG_KEYDESC] = "is %s", ++ ++ /* Control keys. */ ++ /* Most of these duplicate the entries in state names. */ ++ [MSG_CTL_SHIFT] = "shift", ++ [MSG_CTL_ALTGR] = "altgr", ++ [MSG_CTL_CONTROL] = "control", ++ [MSG_CTL_ALT] = "ault", ++ [MSG_CTL_LSHIFT] = "l shift", ++ [MSG_CTL_SPEAKUP] = "speakup", ++ [MSG_CTL_LCONTROL] = "l control", ++ [MSG_CTL_RCONTROL] = "r control", ++ [MSG_CTL_CAPSSHIFT] = "caps shift", ++ ++ /* Color names. */ ++ [MSG_COLOR_BLACK] = "black", ++ [MSG_COLOR_BLUE] = "blue", ++ [MSG_COLOR_GREEN] = "green", ++ [MSG_COLOR_CYAN] = "cyan", ++ [MSG_COLOR_RED] = "red", ++ [MSG_COLOR_MAGENTA] = "magenta", ++ [MSG_COLOR_YELLOW] = "yellow", ++ [MSG_COLOR_WHITE] = "white", ++ [MSG_COLOR_GREY] = "grey", ++ ++ /* Names of key states. */ ++ [MSG_STATE_DOUBLE] = "double", ++ [MSG_STATE_SPEAKUP] = "speakup", ++ [MSG_STATE_ALT] = "alt", ++ [MSG_STATE_CONTROL] = "ctrl", ++ [MSG_STATE_ALTGR] = "altgr", ++ [MSG_STATE_SHIFT] = "shift", ++ ++ /* Key names. */ ++ [MSG_KEYNAME_ESC] = "escape", ++ [MSG_KEYNAME_1] = "1", ++ [MSG_KEYNAME_2] = "2", ++ [MSG_KEYNAME_3] = "3", ++ [MSG_KEYNAME_4] = "4", ++ [MSG_KEYNAME_5] = "5", ++ [MSG_KEYNAME_6] = "6", ++ [MSG_KEYNAME_7] = "7", ++ [MSG_KEYNAME_8] = "8", ++ [MSG_KEYNAME_9] = "9", ++ [MSG_KEYNAME_0] = "0", ++ [MSG_KEYNAME_DASH] = "minus", ++ [MSG_KEYNAME_EQUAL] = "equal", ++ [MSG_KEYNAME_BS] = "back space", ++ [MSG_KEYNAME_TAB] = "tab", ++ [MSG_KEYNAME_Q] = "q", ++ [MSG_KEYNAME_W] = "w", ++ [MSG_KEYNAME_E] = "e", ++ [MSG_KEYNAME_R] = "r", ++ [MSG_KEYNAME_T] = "t", ++ [MSG_KEYNAME_Y] = "y", ++ [MSG_KEYNAME_U] = "u", ++ [MSG_KEYNAME_I] = "i", ++ [MSG_KEYNAME_O] = "o", ++ [MSG_KEYNAME_P] = "p", ++ [MSG_KEYNAME_LEFTBRACE] = "left brace", ++ [MSG_KEYNAME_RIGHTBRACE] = "right brace", ++ [MSG_KEYNAME_ENTER] = "enter", ++ [MSG_KEYNAME_LEFTCTRL] = "left control", ++ [MSG_KEYNAME_A] = "a", ++ [MSG_KEYNAME_S] = "s", ++ [MSG_KEYNAME_D] = "d", ++ [MSG_KEYNAME_F] = "f", ++ [MSG_KEYNAME_G] = "g", ++ [MSG_KEYNAME_H] = "h", ++ [MSG_KEYNAME_J] = "j", ++ [MSG_KEYNAME_K] = "k", ++ [MSG_KEYNAME_L] = "l", ++ [MSG_KEYNAME_SEMICOLON] = "semicolon", ++ [MSG_KEYNAME_SINGLEQUOTE] = "apostrophe", ++ [MSG_KEYNAME_GRAVE] = "accent", ++ [MSG_KEYNAME_LEFTSHFT] = "left shift", ++ [MSG_KEYNAME_BACKSLASH] = "back slash", ++ [MSG_KEYNAME_Z] = "z", ++ [MSG_KEYNAME_X] = "x", ++ [MSG_KEYNAME_C] = "c", ++ [MSG_KEYNAME_V] = "v", ++ [MSG_KEYNAME_B] = "b", ++ [MSG_KEYNAME_N] = "n", ++ [MSG_KEYNAME_M] = "m", ++ [MSG_KEYNAME_COMMA] = "comma", ++ [MSG_KEYNAME_DOT] = "dot", ++ [MSG_KEYNAME_SLASH] = "slash", ++ [MSG_KEYNAME_RIGHTSHFT] = "right shift", ++ [MSG_KEYNAME_KPSTAR] = "keypad asterisk", ++ [MSG_KEYNAME_LEFTALT] = "left alt", ++ [MSG_KEYNAME_SPACE] = "space", ++ [MSG_KEYNAME_CAPSLOCK] = "caps lock", ++ [MSG_KEYNAME_F1] = "f1", ++ [MSG_KEYNAME_F2] = "f2", ++ [MSG_KEYNAME_F3] = "f3", ++ [MSG_KEYNAME_F4] = "f4", ++ [MSG_KEYNAME_F5] = "f5", ++ [MSG_KEYNAME_F6] = "f6", ++ [MSG_KEYNAME_F7] = "f7", ++ [MSG_KEYNAME_F8] = "f8", ++ [MSG_KEYNAME_F9] = "f9", ++ [MSG_KEYNAME_F10] = "f10", ++ [MSG_KEYNAME_NUMLOCK] = "num lock", ++ [MSG_KEYNAME_SCROLLLOCK] = "scroll lock", ++ [MSG_KEYNAME_KP7] = "keypad 7", ++ [MSG_KEYNAME_KP8] = "keypad 8", ++ [MSG_KEYNAME_KP9] = "keypad 9", ++ [MSG_KEYNAME_KPMINUS] = "keypad minus", ++ [MSG_KEYNAME_KP4] = "keypad 4", ++ [MSG_KEYNAME_KP5] = "keypad 5", ++ [MSG_KEYNAME_KP6] = "keypad 6", ++ [MSG_KEYNAME_KPPLUS] = "keypad plus", ++ [MSG_KEYNAME_KP1] = "keypad 1", ++ [MSG_KEYNAME_KP2] = "keypad 2", ++ [MSG_KEYNAME_KP3] = "keypad 3", ++ [MSG_KEYNAME_KP0] = "keypad 0", ++ [MSG_KEYNAME_KPDOT] = "keypad dot", ++ [MSG_KEYNAME_103RD] = "103rd", ++ [MSG_KEYNAME_F13] = "f13", ++ [MSG_KEYNAME_102ND] = "102nd", ++ [MSG_KEYNAME_F11] = "f11", ++ [MSG_KEYNAME_F12] = "f12", ++ [MSG_KEYNAME_F14] = "f14", ++ [MSG_KEYNAME_F15] = "f15", ++ [MSG_KEYNAME_F16] = "f16", ++ [MSG_KEYNAME_F17] = "f17", ++ [MSG_KEYNAME_F18] = "f18", ++ [MSG_KEYNAME_F19] = "f19", ++ [MSG_KEYNAME_F20] = "f20", ++ [MSG_KEYNAME_KPENTER] = "keypad enter", ++ [MSG_KEYNAME_RIGHTCTRL] = "right control", ++ [MSG_KEYNAME_KPSLASH] = "keypad slash", ++ [MSG_KEYNAME_SYSRQ] = "sysrq", ++ [MSG_KEYNAME_RIGHTALT] = "right alt", ++ [MSG_KEYNAME_LF] = "line feed", ++ [MSG_KEYNAME_HOME] = "home", ++ [MSG_KEYNAME_UP] = "up", ++ [MSG_KEYNAME_PGUP] = "page up", ++ [MSG_KEYNAME_LEFT] = "left", ++ [MSG_KEYNAME_RIGHT] = "right", ++ [MSG_KEYNAME_END] = "end", ++ [MSG_KEYNAME_DOWN] = "down", ++ [MSG_KEYNAME_PGDN] = "page down", ++ [MSG_KEYNAME_INS] = "insert", ++ [MSG_KEYNAME_DEL] = "delete", ++ [MSG_KEYNAME_MACRO] = "macro", ++ [MSG_KEYNAME_MUTE] = "mute", ++ [MSG_KEYNAME_VOLDOWN] = "volume down", ++ [MSG_KEYNAME_VOLUP] = "volume up", ++ [MSG_KEYNAME_POWER] = "power", ++ [MSG_KEYNAME_KPEQUAL] = "keypad equal", ++ [MSG_KEYNAME_KPPLUSDASH] = "keypad plusminus", ++ [MSG_KEYNAME_PAUSE] = "pause", ++ [MSG_KEYNAME_F21] = "f21", ++ [MSG_KEYNAME_F22] = "f22", ++ [MSG_KEYNAME_F23] = "f23", ++ [MSG_KEYNAME_F24] = "f24", ++ [MSG_KEYNAME_KPCOMMA] = "keypad comma", ++ [MSG_KEYNAME_LEFTMETA] = "left meta", ++ [MSG_KEYNAME_RIGHTMETA] = "right meta", ++ [MSG_KEYNAME_COMPOSE] = "compose", ++ [MSG_KEYNAME_STOP] = "stop", ++ [MSG_KEYNAME_AGAIN] = "again", ++ [MSG_KEYNAME_PROPS] = "props", ++ [MSG_KEYNAME_UNDO] = "undo", ++ [MSG_KEYNAME_FRONT] = "front", ++ [MSG_KEYNAME_COPY] = "copy", ++ [MSG_KEYNAME_OPEN] = "open", ++ [MSG_KEYNAME_PASTE] = "paste", ++ [MSG_KEYNAME_FIND] = "find", ++ [MSG_KEYNAME_CUT] = "cut", ++ [MSG_KEYNAME_HELP] = "help", ++ [MSG_KEYNAME_MENU] = "menu", ++ [MSG_KEYNAME_CALC] = "calc", ++ [MSG_KEYNAME_SETUP] = "setup", ++ [MSG_KEYNAME_SLEEP] = "sleep", ++ [MSG_KEYNAME_WAKEUP] = "wakeup", ++ [MSG_KEYNAME_FILE] = "file", ++ [MSG_KEYNAME_SENDFILE] = "send file", ++ [MSG_KEYNAME_DELFILE] = "delete file", ++ [MSG_KEYNAME_XFER] = "transfer", ++ [MSG_KEYNAME_PROG1] = "prog1", ++ [MSG_KEYNAME_PROG2] = "prog2", ++ [MSG_KEYNAME_WWW] = "www", ++ [MSG_KEYNAME_MSDOS] = "msdos", ++ [MSG_KEYNAME_COFFEE] = "coffee", ++ [MSG_KEYNAME_DIRECTION] = "direction", ++ [MSG_KEYNAME_CYCLEWINDOWS] = "cycle windows", ++ [MSG_KEYNAME_MAIL] = "mail", ++ [MSG_KEYNAME_BOOKMARKS] = "bookmarks", ++ [MSG_KEYNAME_COMPUTER] = "computer", ++ [MSG_KEYNAME_BACK] = "back", ++ [MSG_KEYNAME_FORWARD] = "forward", ++ [MSG_KEYNAME_CLOSECD] = "close cd", ++ [MSG_KEYNAME_EJECTCD] = "eject cd", ++ [MSG_KEYNAME_EJECTCLOSE] = "eject close cd", ++ [MSG_KEYNAME_NEXTSONG] = "next song", ++ [MSG_KEYNAME_PLAYPAUSE] = "play pause", ++ [MSG_KEYNAME_PREVSONG] = "previous song", ++ [MSG_KEYNAME_STOPCD] = "stop cd", ++ [MSG_KEYNAME_RECORD] = "record", ++ [MSG_KEYNAME_REWIND] = "rewind", ++ [MSG_KEYNAME_PHONE] = "phone", ++ [MSG_KEYNAME_ISO] = "iso", ++ [MSG_KEYNAME_CONFIG] = "config", ++ [MSG_KEYNAME_HOMEPG] = "home page", ++ [MSG_KEYNAME_REFRESH] = "refresh", ++ [MSG_KEYNAME_EXIT] = "exit", ++ [MSG_KEYNAME_MOVE] = "move", ++ [MSG_KEYNAME_EDIT] = "edit", ++ [MSG_KEYNAME_SCROLLUP] = "scroll up", ++ [MSG_KEYNAME_SCROLLDN] = "scroll down", ++ [MSG_KEYNAME_KPLEFTPAR] = "keypad left paren", ++ [MSG_KEYNAME_KPRIGHTPAR] = "keypad right paren", ++ ++ /* Function names. */ ++ [MSG_FUNCNAME_ATTRIB_BLEEP_DEC] = "attribute bleep decrement", ++ [MSG_FUNCNAME_ATTRIB_BLEEP_INC] = "attribute bleep increment", ++ [MSG_FUNCNAME_BLEEPS_DEC] = "bleeps decrement", ++ [MSG_FUNCNAME_BLEEPS_INC] = "bleeps increment", ++ [MSG_FUNCNAME_CHAR_FIRST] = "character, first", ++ [MSG_FUNCNAME_CHAR_LAST] = "character, last", ++ [MSG_FUNCNAME_CHAR_CURRENT] = "character, say current", ++ [MSG_FUNCNAME_CHAR_HEX_AND_DEC] = "character, say hex and decimal", ++ [MSG_FUNCNAME_CHAR_NEXT] = "character, say next", ++ [MSG_FUNCNAME_CHAR_PHONETIC] = "character, say phonetic", ++ [MSG_FUNCNAME_CHAR_PREVIOUS] = "character, say previous", ++ [MSG_FUNCNAME_CURSOR_PARK] = "cursor park", ++ [MSG_FUNCNAME_CUT] = "cut", ++ [MSG_FUNCNAME_EDIT_DELIM] = "edit delimiters", ++ [MSG_FUNCNAME_EDIT_EXNUM] = "edit exnum", ++ [MSG_FUNCNAME_EDIT_MOST] = "edit most", ++ [MSG_FUNCNAME_EDIT_REPEATS] = "edit repeats", ++ [MSG_FUNCNAME_EDIT_SOME] = "edit some", ++ [MSG_FUNCNAME_GOTO] = "go to", ++ [MSG_FUNCNAME_GOTO_BOTTOM] = "go to bottom edge", ++ [MSG_FUNCNAME_GOTO_LEFT] = "go to left edge", ++ [MSG_FUNCNAME_GOTO_RIGHT] = "go to right edge", ++ [MSG_FUNCNAME_GOTO_TOP] = "go to top edge", ++ [MSG_FUNCNAME_HELP] = "help", ++ [MSG_FUNCNAME_LINE_SAY_CURRENT] = "line, say current", ++ [MSG_FUNCNAME_LINE_SAY_NEXT] = "line, say next", ++ [MSG_FUNCNAME_LINE_SAY_PREVIOUS] = "line, say previous", ++ [MSG_FUNCNAME_LINE_SAY_WITH_INDENT] = "line, say with indent", ++ [MSG_FUNCNAME_PASTE] = "paste", ++ [MSG_FUNCNAME_PITCH_DEC] = "pitch decrement", ++ [MSG_FUNCNAME_PITCH_INC] = "pitch increment", ++ [MSG_FUNCNAME_PUNC_DEC] = "punctuation decrement", ++ [MSG_FUNCNAME_PUNC_INC] = "punctuation increment", ++ [MSG_FUNCNAME_PUNC_LEVEL_DEC] = "punc level decrement", ++ [MSG_FUNCNAME_PUNC_LEVEL_INC] = "punc level increment", ++ [MSG_FUNCNAME_QUIET] = "quiet", ++ [MSG_FUNCNAME_RATE_DEC] = "rate decrement", ++ [MSG_FUNCNAME_RATE_INC] = "rate increment", ++ [MSG_FUNCNAME_READING_PUNC_DEC] = "reading punctuation decrement", ++ [MSG_FUNCNAME_READING_PUNC_INC] = "reading punctuation increment", ++ [MSG_FUNCNAME_SAY_ATTRIBUTES] = "say attributes", ++ [MSG_FUNCNAME_SAY_FROM_LEFT] = "say from left", ++ [MSG_FUNCNAME_SAY_FROM_TOP] = "say from top", ++ [MSG_FUNCNAME_SAY_POSITION] = "say position", ++ [MSG_FUNCNAME_SAY_SCREEN] = "say screen", ++ [MSG_FUNCNAME_SAY_TO_BOTTOM] = "say to bottom", ++ [MSG_FUNCNAME_SAY_TO_RIGHT] = "say to right", ++ [MSG_FUNCNAME_SPEAKUP] = "speakup", ++ [MSG_FUNCNAME_SPEAKUP_LOCK] = "speakup lock", ++ [MSG_FUNCNAME_SPEAKUP_OFF] = "speakup off", ++ [MSG_FUNCNAME_SPEECH_KILL] = "speech kill", ++ [MSG_FUNCNAME_SPELL_DELAY_DEC] = "spell delay decrement", ++ [MSG_FUNCNAME_SPELL_DELAY_INC] = "spell delay increment", ++ [MSG_FUNCNAME_SPELL_WORD] = "spell word", ++ [MSG_FUNCNAME_SPELL_WORD_PHONETICALLY] = "spell word phoneticly", ++ [MSG_FUNCNAME_TONE_DEC] = "tone decrement", ++ [MSG_FUNCNAME_TONE_INC] = "tone increment", ++ [MSG_FUNCNAME_VOICE_DEC] = "voice decrement", ++ [MSG_FUNCNAME_VOICE_INC] = "voice increment", ++ [MSG_FUNCNAME_VOLUME_DEC] = "volume decrement", ++ [MSG_FUNCNAME_VOLUME_INC] = "volume increment", ++ [MSG_FUNCNAME_WINDOW_CLEAR] = "window, clear", ++ [MSG_FUNCNAME_WINDOW_SAY] = "window, say", ++ [MSG_FUNCNAME_WINDOW_SET] = "window, set", ++ [MSG_FUNCNAME_WINDOW_SILENCE] = "window, silence", ++ [MSG_FUNCNAME_WORD_SAY_CURRENT] = "word, say current", ++ [MSG_FUNCNAME_WORD_SAY_NEXT] = "word, say next", ++ [MSG_FUNCNAME_WORD_SAY_PREVIOUS] = "word, say previous", ++}; ++ ++static struct msg_group_t all_groups [] = { ++ { ++ .name = "ctl_keys", ++ .start = MSG_CTL_START, ++ .end = MSG_CTL_END, ++ }, ++ { ++ .name = "colors", ++ .start = MSG_COLORS_START, ++ .end = MSG_COLORS_END, ++ }, ++ { ++ .name = "formatted", ++ .start = MSG_FORMATTED_START, ++ .end = MSG_FORMATTED_END, ++ }, ++ { ++ .name = "function_names", ++ .start = MSG_FUNCNAMES_START, ++ .end = MSG_FUNCNAMES_END, ++ }, ++ { ++ .name = "key_names", ++ .start = MSG_KEYNAMES_START, ++ .end = MSG_KEYNAMES_END, ++ }, ++ { ++ .name = "announcements", ++ .start = MSG_ANNOUNCEMENTS_START, ++ .end = MSG_ANNOUNCEMENTS_END, ++ }, ++ { ++ .name = "states", ++ .start = MSG_STATES_START, ++ .end = MSG_STATES_END, ++ }, ++}; ++ ++static const int num_groups = sizeof(all_groups) / sizeof(struct msg_group_t); ++ ++char *msg_get(enum msg_index_t index) ++{ ++ char *ch; ++ ++ ch = speakup_msgs[index]; ++ return ch; ++} ++ ++/* ++ * Function: next_specifier ++ * Finds the start of the next format specifier in the argument string. ++ * Return value: pointer to start of format ++ * specifier, or NULL if no specifier exists. ++*/ ++static char *next_specifier(char *input) ++{ ++ int found = 0; ++ char *next_percent = input; ++ ++ while ((next_percent != NULL) && !found) { ++ next_percent = strchr(next_percent, '%'); ++ if (next_percent != NULL) { ++ while ((next_percent[0] == '%') ++ && (next_percent[1] == '%')) ++ next_percent += 2; /* Advance over doubled percent signs. */ ++ if (*next_percent == '%') ++ found = 1; ++ else if (*next_percent == '\0') ++ next_percent = NULL; ++ } ++ } ++ ++ return next_percent; ++} ++ ++/* Skip over 0 or more flags. */ ++static char *skip_flags(char *input) ++{ ++ while ((*input != '\0') && strchr(" 0+-#", *input)) ++ input++; ++ return input; ++} ++ ++/* Skip over width.precision, if it exists. */ ++static char *skip_width(char *input) ++{ ++ while (isdigit(*input)) ++ input++; ++ if (*input == '.') { ++ input++; ++ while (isdigit(*input)) ++ input++; ++ } ++ return input; ++} ++ ++/* ++ * Skip past the end of the conversion part. ++ * Note that this code only accepts a handful of conversion specifiers: ++ * c d s x and ld. Not accidental; these are exactly the ones used in ++ * the default group of formatted messages. ++*/ ++static char *skip_conversion(char *input) ++{ ++ if ((input[0] == 'l') && (input[1] == 'd')) ++ input += 2; ++ else if ((*input != '\0') && strchr("cdsx", *input)) ++ input++; ++ return input; ++} ++ ++/* ++ * Function: find_specifier_end ++ * Return a pointer to the end of the format specifier. ++*/ ++static char *find_specifier_end(char *input) ++{ ++ input++; /* Advance over %. */ ++ input = skip_flags(input); ++ input = skip_width(input); ++ input = skip_conversion(input); ++ return input; ++} ++ ++/* ++ * Function: compare_specifiers ++ * Compare the format specifiers pointed to by *input1 and *input2. ++ * Return 1 if they are the same, 0 otherwise. Advance *input1 and *input2 ++ * so that they point to the character following the end of the specifier. ++*/ ++static int compare_specifiers(char **input1, char **input2) ++{ ++ int same = 0; ++ char *end1 = find_specifier_end(*input1); ++ char *end2 = find_specifier_end(*input2); ++ size_t length1 = end1 - *input1; ++ size_t length2 = end2 - *input2; ++ ++ if((length1 == length2) && !memcmp(*input1, *input2, length1)) ++ same = 1; ++ ++ *input1 = end1; ++ *input2 = end2; ++ return same; ++} ++ ++/* ++ * Function: fmt_validate ++ * Check that two format strings contain the same number of format specifiers, ++ * and that the order of specifiers is the same in both strings. ++ * Return 1 if the condition holds, 0 if it doesn't. ++*/ ++static int fmt_validate(char *template, char *user) ++{ ++ int valid = 1; ++ int still_comparing = 1; ++ char *template_ptr = template; ++ char *user_ptr = user; ++ ++ while (still_comparing && valid) { ++ template_ptr = next_specifier(template_ptr); ++ user_ptr = next_specifier(user_ptr); ++ if (template_ptr && user_ptr) { ++/* Both have at least one more specifier. */ ++ valid = compare_specifiers(&template_ptr, &user_ptr); ++ } else { ++/* No more format specifiers in one or both of the strings. */ ++ still_comparing = 0; ++ if (template_ptr || user_ptr) ++ valid = 0; /* One has more specifiers than the other. */ ++ } ++ } ++ return valid; ++} ++ ++/* ++ * Function: msg_set ++ * Description: Add a user-supplied message to the user_messages array. ++ * The message text is copied to a memory area allocated with kmalloc. ++ * If the function fails, then user_messages is untouched. ++ * Arguments: ++ * - index: a message number, as found in i18n.h. ++ * - text: text of message. Not NUL-terminated. ++ * - length: number of bytes in text. ++ * Failure conditions: ++ * -EINVAL - Invalid format specifiers in formatted message or illegal index. ++ * -ENOMEM - Unable to allocate memory. ++*/ ++ssize_t msg_set(enum msg_index_t index, char *text, size_t length) ++{ ++ int rc = 0; ++ char *newstr = NULL; ++ unsigned long flags; ++ ++ if ((index >= MSG_FIRST_INDEX) && (index < MSG_LAST_INDEX)) { ++ newstr = kmalloc(length + 1, GFP_KERNEL); ++ if (newstr) { ++ memcpy(newstr, text, length); ++ newstr[length] = '\0'; ++ if ((index >= MSG_FORMATTED_START && index <= MSG_FORMATTED_END) ++ && ! fmt_validate(speakup_default_msgs[index], newstr)) { ++ return -EINVAL; ++ } ++ spk_lock(flags); ++ if (speakup_msgs[index] != speakup_default_msgs[index]) ++ kfree(speakup_msgs[index]); ++ speakup_msgs[index] = newstr; ++ spk_unlock(flags); ++ } else { ++ rc = -ENOMEM; ++ } ++ } else { ++ rc = -EINVAL; ++ } ++ return rc; ++} ++ ++/* ++ * Find a message group, given its name. Return a pointer to the structure ++ * if found, or NULL otherwise. ++*/ ++struct msg_group_t *find_msg_group(const char *group_name) ++{ ++ struct msg_group_t *group = NULL; ++ int i; ++ ++ for (i = 0; i < num_groups; i++) { ++ if (!strcmp(all_groups[i].name, group_name)) { ++ group = &all_groups[i]; ++ break; ++ } ++ } ++ return group; ++} ++ ++void reset_msg_group(struct msg_group_t *group) ++{ ++ unsigned long flags; ++ enum msg_index_t i; ++ ++ spk_lock(flags); ++ ++ for(i = group->start; i <= group->end; i++) { ++ if (speakup_msgs[i] != speakup_default_msgs[i]) ++ kfree(speakup_msgs[i]); ++ speakup_msgs[i] = speakup_default_msgs[i]; ++ } ++ spk_unlock(flags); ++} ++ ++/* Called at initialization time, to establish default messages. */ ++void initialize_msgs(void) ++{ ++ memcpy(speakup_msgs, speakup_default_msgs, sizeof(speakup_default_msgs)); ++} ++ ++/* Free user-supplied strings when module is unloaded: */ ++void free_user_msgs(void) ++{ ++ enum msg_index_t index; ++ unsigned long flags; ++ ++ spk_lock(flags); ++ for(index = MSG_FIRST_INDEX; index < MSG_LAST_INDEX; index++) { ++ if (speakup_msgs[index] != speakup_default_msgs[index]) { ++ kfree(speakup_msgs[index]); ++ speakup_msgs[index] = speakup_default_msgs[index]; ++ } ++ } ++ spk_unlock(flags); ++} +--- a/drivers/staging/speakup/i18n.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/i18n.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,228 @@ ++#ifndef I18N_H ++#define I18N_H ++/* Internationalization declarations */ ++ ++enum msg_index_t { ++ MSG_FIRST_INDEX , ++ MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX, ++ MSG_BLANK = MSG_ANNOUNCEMENTS_START, ++ MSG_IAM_ALIVE, ++ MSG_YOU_KILLED_SPEAKUP, ++ MSG_HEY_THATS_BETTER, ++ MSG_YOU_TURNED_ME_OFF, ++ MSG_PARKED, ++ MSG_UNPARKED, ++ MSG_MARK, ++ MSG_CUT, ++ MSG_MARK_CLEARED, ++ MSG_PASTE, ++ MSG_BRIGHT, ++ MSG_ON_BLINKING, ++ MSG_STATUS_START, ++ MSG_OFF = MSG_STATUS_START, ++ MSG_ON, ++ MSG_NO_WINDOW, ++ MSG_CURSOR_MSGS_START, ++ MSG_CURSORING_OFF = MSG_CURSOR_MSGS_START, ++ MSG_CURSORING_ON, ++ MSG_HIGHLIGHT_TRACKING, ++ MSG_READ_WINDOW, ++ MSG_READ_ALL, ++ MSG_EDIT_DONE, ++ MSG_WINDOW_ALREADY_SET, ++ MSG_END_BEFORE_START, ++ MSG_WINDOW_CLEARED, ++ MSG_WINDOW_SILENCED, ++ MSG_WINDOW_SILENCE_DISABLED, ++ MSG_ERROR, ++ MSG_GOTO_CANCELED, ++ MSG_GOTO, ++ MSG_LEAVING_HELP, ++ MSG_IS_UNASSIGNED, ++ MSG_HELP_INFO, ++ MSG_EDGE_MSGS_START, ++ MSG_EDGE_TOP = MSG_EDGE_MSGS_START, ++ MSG_EDGE_BOTTOM, ++ MSG_EDGE_LEFT, ++ MSG_EDGE_RIGHT, ++ MSG_NUMBER, ++ MSG_SPACE, ++ MSG_START, /* A little confusing, given our convention. */ ++ MSG_END, /* A little confusing, given our convention. */ ++ MSG_CTRL, ++ ++/* A message containing the single word "or". */ ++ MSG_DISJUNCTION, ++ MSG_ANNOUNCEMENTS_END = MSG_DISJUNCTION, ++ ++/* Messages with format specifiers. */ ++ MSG_FORMATTED_START, ++ MSG_POS_INFO = MSG_FORMATTED_START, ++ MSG_CHAR_INFO, ++ MSG_REPEAT_DESC, ++ MSG_REPEAT_DESC2, ++ MSG_WINDOW_LINE, ++ MSG_WINDOW_BOUNDARY, ++ MSG_EDIT_PROMPT, ++ MSG_NO_COMMAND, ++ MSG_KEYDESC, ++ MSG_FORMATTED_END = MSG_KEYDESC, ++ ++ /* Control keys. */ ++ MSG_CTL_START, ++ MSG_CTL_SHIFT = MSG_CTL_START, ++ MSG_CTL_ALTGR, ++ MSG_CTL_CONTROL, ++ MSG_CTL_ALT, ++ MSG_CTL_LSHIFT, ++ MSG_CTL_SPEAKUP, ++ MSG_CTL_LCONTROL, ++ MSG_CTL_RCONTROL, ++ MSG_CTL_CAPSSHIFT, ++ MSG_CTL_END = MSG_CTL_CAPSSHIFT, ++ ++ /* Colors. */ ++ MSG_COLORS_START, ++ MSG_COLOR_BLACK = MSG_COLORS_START, ++ MSG_COLOR_BLUE, ++ MSG_COLOR_GREEN, ++ MSG_COLOR_CYAN, ++ MSG_COLOR_RED, ++ MSG_COLOR_MAGENTA, ++ MSG_COLOR_YELLOW, ++ MSG_COLOR_WHITE, ++ MSG_COLOR_GREY, ++ MSG_COLORS_END = MSG_COLOR_GREY, ++ ++ MSG_STATES_START, ++ MSG_STATE_DOUBLE = MSG_STATES_START, ++ MSG_STATE_SPEAKUP, ++ MSG_STATE_ALT, ++ MSG_STATE_CONTROL, ++ MSG_STATE_ALTGR, ++ MSG_STATE_SHIFT, ++ MSG_STATES_END = MSG_STATE_SHIFT, ++ ++ MSG_KEYNAMES_START, ++ MSG_KEYNAME_ESC = MSG_KEYNAMES_START, ++ MSG_KEYNAME_1, MSG_KEYNAME_2, MSG_KEYNAME_3, MSG_KEYNAME_4, ++ MSG_KEYNAME_5, MSG_KEYNAME_6, MSG_KEYNAME_7, MSG_KEYNAME_8, MSG_KEYNAME_9, ++ MSG_KEYNAME_0, MSG_KEYNAME_DASH, MSG_KEYNAME_EQUAL, MSG_KEYNAME_BS, ++ MSG_KEYNAME_TAB, ++ MSG_KEYNAME_Q, MSG_KEYNAME_W, MSG_KEYNAME_E, MSG_KEYNAME_R, MSG_KEYNAME_T, ++ MSG_KEYNAME_Y, MSG_KEYNAME_U, MSG_KEYNAME_I, MSG_KEYNAME_O, MSG_KEYNAME_P, ++ MSG_KEYNAME_LEFTBRACE, MSG_KEYNAME_RIGHTBRACE, MSG_KEYNAME_ENTER, ++ MSG_KEYNAME_LEFTCTRL, MSG_KEYNAME_A, ++ MSG_KEYNAME_S, MSG_KEYNAME_D, MSG_KEYNAME_F, MSG_KEYNAME_G, MSG_KEYNAME_H, ++ MSG_KEYNAME_J, MSG_KEYNAME_K, MSG_KEYNAME_L, MSG_KEYNAME_SEMICOLON, ++ MSG_KEYNAME_SINGLEQUOTE, MSG_KEYNAME_GRAVE, ++ MSG_KEYNAME_LEFTSHFT, MSG_KEYNAME_BACKSLASH, MSG_KEYNAME_Z, MSG_KEYNAME_X, ++ MSG_KEYNAME_C, MSG_KEYNAME_V, MSG_KEYNAME_B, MSG_KEYNAME_N, MSG_KEYNAME_M, ++ MSG_KEYNAME_COMMA, MSG_KEYNAME_DOT, MSG_KEYNAME_SLASH, MSG_KEYNAME_RIGHTSHFT, ++ MSG_KEYNAME_KPSTAR, ++ MSG_KEYNAME_LEFTALT, MSG_KEYNAME_SPACE, MSG_KEYNAME_CAPSLOCK, ++ MSG_KEYNAME_F1, MSG_KEYNAME_F2, ++ MSG_KEYNAME_F3, MSG_KEYNAME_F4, MSG_KEYNAME_F5, MSG_KEYNAME_F6, ++ MSG_KEYNAME_F7, ++ MSG_KEYNAME_F8, MSG_KEYNAME_F9, MSG_KEYNAME_F10, MSG_KEYNAME_NUMLOCK, ++ MSG_KEYNAME_SCROLLLOCK, ++ MSG_KEYNAME_KP7, MSG_KEYNAME_KP8, MSG_KEYNAME_KP9, MSG_KEYNAME_KPMINUS, ++ MSG_KEYNAME_KP4, ++ MSG_KEYNAME_KP5, MSG_KEYNAME_KP6, MSG_KEYNAME_KPPLUS, MSG_KEYNAME_KP1, ++ MSG_KEYNAME_KP2, ++ MSG_KEYNAME_KP3, MSG_KEYNAME_KP0, MSG_KEYNAME_KPDOT, MSG_KEYNAME_103RD, ++ MSG_KEYNAME_F13, ++ MSG_KEYNAME_102ND, MSG_KEYNAME_F11, MSG_KEYNAME_F12, MSG_KEYNAME_F14, ++ MSG_KEYNAME_F15, ++ MSG_KEYNAME_F16, MSG_KEYNAME_F17, MSG_KEYNAME_F18, MSG_KEYNAME_F19, ++ MSG_KEYNAME_F20, ++ MSG_KEYNAME_KPENTER, MSG_KEYNAME_RIGHTCTRL, MSG_KEYNAME_KPSLASH, ++ MSG_KEYNAME_SYSRQ, MSG_KEYNAME_RIGHTALT, ++ MSG_KEYNAME_LF, MSG_KEYNAME_HOME, MSG_KEYNAME_UP, MSG_KEYNAME_PGUP, ++ MSG_KEYNAME_LEFT, ++ MSG_KEYNAME_RIGHT, MSG_KEYNAME_END, MSG_KEYNAME_DOWN, MSG_KEYNAME_PGDN, ++ MSG_KEYNAME_INS, ++ MSG_KEYNAME_DEL, MSG_KEYNAME_MACRO, MSG_KEYNAME_MUTE, ++ MSG_KEYNAME_VOLDOWN, MSG_KEYNAME_VOLUP, ++ MSG_KEYNAME_POWER, MSG_KEYNAME_KPEQUAL, MSG_KEYNAME_KPPLUSDASH, MSG_KEYNAME_PAUSE, MSG_KEYNAME_F21, ++ MSG_KEYNAME_F22, MSG_KEYNAME_F23, MSG_KEYNAME_F24, MSG_KEYNAME_KPCOMMA, MSG_KEYNAME_LEFTMETA, ++ MSG_KEYNAME_RIGHTMETA, MSG_KEYNAME_COMPOSE, MSG_KEYNAME_STOP, ++ MSG_KEYNAME_AGAIN, MSG_KEYNAME_PROPS, ++ MSG_KEYNAME_UNDO, MSG_KEYNAME_FRONT, MSG_KEYNAME_COPY, MSG_KEYNAME_OPEN, ++ MSG_KEYNAME_PASTE, ++ MSG_KEYNAME_FIND, MSG_KEYNAME_CUT, MSG_KEYNAME_HELP, MSG_KEYNAME_MENU, ++ MSG_KEYNAME_CALC, ++ MSG_KEYNAME_SETUP, MSG_KEYNAME_SLEEP, MSG_KEYNAME_WAKEUP, ++ MSG_KEYNAME_FILE, MSG_KEYNAME_SENDFILE, ++ MSG_KEYNAME_DELFILE, MSG_KEYNAME_XFER, MSG_KEYNAME_PROG1, ++ MSG_KEYNAME_PROG2, MSG_KEYNAME_WWW, ++ MSG_KEYNAME_MSDOS, MSG_KEYNAME_COFFEE, MSG_KEYNAME_DIRECTION, ++ MSG_KEYNAME_CYCLEWINDOWS, MSG_KEYNAME_MAIL, ++ MSG_KEYNAME_BOOKMARKS, MSG_KEYNAME_COMPUTER, MSG_KEYNAME_BACK, ++ MSG_KEYNAME_FORWARD, MSG_KEYNAME_CLOSECD, ++ MSG_KEYNAME_EJECTCD, MSG_KEYNAME_EJECTCLOSE, MSG_KEYNAME_NEXTSONG, ++ MSG_KEYNAME_PLAYPAUSE, MSG_KEYNAME_PREVSONG, ++ MSG_KEYNAME_STOPCD, MSG_KEYNAME_RECORD, MSG_KEYNAME_REWIND, ++ MSG_KEYNAME_PHONE, MSG_KEYNAME_ISO, ++ MSG_KEYNAME_CONFIG, MSG_KEYNAME_HOMEPG, MSG_KEYNAME_REFRESH, ++ MSG_KEYNAME_EXIT, MSG_KEYNAME_MOVE, ++ MSG_KEYNAME_EDIT, MSG_KEYNAME_SCROLLUP, MSG_KEYNAME_SCROLLDN, ++ MSG_KEYNAME_KPLEFTPAR, MSG_KEYNAME_KPRIGHTPAR, ++ MSG_KEYNAMES_END = MSG_KEYNAME_KPRIGHTPAR, ++ ++ MSG_FUNCNAMES_START, ++ MSG_FUNCNAME_ATTRIB_BLEEP_DEC = MSG_FUNCNAMES_START, ++ MSG_FUNCNAME_ATTRIB_BLEEP_INC, ++ MSG_FUNCNAME_BLEEPS_DEC, MSG_FUNCNAME_BLEEPS_INC, ++ MSG_FUNCNAME_CHAR_FIRST, MSG_FUNCNAME_CHAR_LAST, ++ MSG_FUNCNAME_CHAR_CURRENT, MSG_FUNCNAME_CHAR_HEX_AND_DEC, ++ MSG_FUNCNAME_CHAR_NEXT, ++ MSG_FUNCNAME_CHAR_PHONETIC, MSG_FUNCNAME_CHAR_PREVIOUS, ++ MSG_FUNCNAME_CURSOR_PARK, MSG_FUNCNAME_CUT, ++ MSG_FUNCNAME_EDIT_DELIM, MSG_FUNCNAME_EDIT_EXNUM, ++ MSG_FUNCNAME_EDIT_MOST, MSG_FUNCNAME_EDIT_REPEATS, MSG_FUNCNAME_EDIT_SOME, ++ MSG_FUNCNAME_GOTO, MSG_FUNCNAME_GOTO_BOTTOM, MSG_FUNCNAME_GOTO_LEFT, ++ MSG_FUNCNAME_GOTO_RIGHT, MSG_FUNCNAME_GOTO_TOP, MSG_FUNCNAME_HELP, ++ MSG_FUNCNAME_LINE_SAY_CURRENT, MSG_FUNCNAME_LINE_SAY_NEXT, ++ MSG_FUNCNAME_LINE_SAY_PREVIOUS, MSG_FUNCNAME_LINE_SAY_WITH_INDENT, ++ MSG_FUNCNAME_PASTE, MSG_FUNCNAME_PITCH_DEC, MSG_FUNCNAME_PITCH_INC, ++ MSG_FUNCNAME_PUNC_DEC, MSG_FUNCNAME_PUNC_INC, ++ MSG_FUNCNAME_PUNC_LEVEL_DEC, MSG_FUNCNAME_PUNC_LEVEL_INC, ++ MSG_FUNCNAME_QUIET, ++ MSG_FUNCNAME_RATE_DEC, MSG_FUNCNAME_RATE_INC, ++ MSG_FUNCNAME_READING_PUNC_DEC, MSG_FUNCNAME_READING_PUNC_INC, ++ MSG_FUNCNAME_SAY_ATTRIBUTES, ++ MSG_FUNCNAME_SAY_FROM_LEFT, MSG_FUNCNAME_SAY_FROM_TOP, ++ MSG_FUNCNAME_SAY_POSITION, MSG_FUNCNAME_SAY_SCREEN, ++ MSG_FUNCNAME_SAY_TO_BOTTOM, MSG_FUNCNAME_SAY_TO_RIGHT, ++ MSG_FUNCNAME_SPEAKUP, MSG_FUNCNAME_SPEAKUP_LOCK, ++ MSG_FUNCNAME_SPEAKUP_OFF, MSG_FUNCNAME_SPEECH_KILL, ++ MSG_FUNCNAME_SPELL_DELAY_DEC, MSG_FUNCNAME_SPELL_DELAY_INC, ++ MSG_FUNCNAME_SPELL_WORD, MSG_FUNCNAME_SPELL_WORD_PHONETICALLY, ++ MSG_FUNCNAME_TONE_DEC, MSG_FUNCNAME_TONE_INC, ++ MSG_FUNCNAME_VOICE_DEC, MSG_FUNCNAME_VOICE_INC, ++ MSG_FUNCNAME_VOLUME_DEC, MSG_FUNCNAME_VOLUME_INC, ++ MSG_FUNCNAME_WINDOW_CLEAR, MSG_FUNCNAME_WINDOW_SAY, ++ MSG_FUNCNAME_WINDOW_SET, MSG_FUNCNAME_WINDOW_SILENCE, ++ MSG_FUNCNAME_WORD_SAY_CURRENT, MSG_FUNCNAME_WORD_SAY_NEXT, ++ MSG_FUNCNAME_WORD_SAY_PREVIOUS, ++ MSG_FUNCNAMES_END = MSG_FUNCNAME_WORD_SAY_PREVIOUS, ++ ++ /* all valid indices must be above this */ ++ MSG_LAST_INDEX ++}; ++ ++struct msg_group_t { ++ char *name; ++ enum msg_index_t start; ++ enum msg_index_t end; ++}; ++ ++extern char *msg_get(enum msg_index_t index); ++extern ssize_t msg_set(enum msg_index_t index, char *text, size_t length); ++extern struct msg_group_t *find_msg_group(const char *group_name); ++extern void reset_msg_group(struct msg_group_t *group); ++extern void initialize_msgs(void); ++extern void free_user_msgs(void); ++ ++#endif +--- a/drivers/staging/speakup/Kbuild 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/Kbuild 2009-10-04 16:44:13.000000000 +0100 +@@ -0,0 +1,29 @@ ++include $M/allmodule.mk ++obj-$(CONFIG_SPEAKUP_SYNTH_ACNTSA) += speakup_acntsa.o ++obj-$(CONFIG_SPEAKUP_SYNTH_ACNTPC) += speakup_acntpc.o ++obj-$(CONFIG_SPEAKUP_SYNTH_APOLLO) += speakup_apollo.o ++obj-$(CONFIG_SPEAKUP_SYNTH_AUDPTR) += speakup_audptr.o ++obj-$(CONFIG_SPEAKUP_SYNTH_BNS) += speakup_bns.o ++obj-$(CONFIG_SPEAKUP_SYNTH_DECTLK) += speakup_dectlk.o ++obj-$(CONFIG_SPEAKUP_SYNTH_DECEXT) += speakup_decext.o ++obj-$(CONFIG_SPEAKUP_SYNTH_DTLK) += speakup_dtlk.o ++obj-$(CONFIG_SPEAKUP_SYNTH_KEYPC) += speakup_keypc.o ++obj-$(CONFIG_SPEAKUP_SYNTH_LTLK) += speakup_ltlk.o ++obj-$(CONFIG_SPEAKUP_SYNTH_SOFT) += speakup_soft.o ++obj-$(CONFIG_SPEAKUP_SYNTH_SPKOUT) += speakup_spkout.o ++obj-$(CONFIG_SPEAKUP_SYNTH_TXPRT) += speakup_txprt.o ++obj-$(CONFIG_SPEAKUP_SYNTH_DUMMY) += speakup_dummy.o ++ ++obj-$(CONFIG_SPEAKUP) += speakup.o ++speakup-objs := \ ++ buffers.o \ ++ devsynth.o \ ++ i18n.o \ ++ main.o \ ++ keyhelp.o \ ++ kobjects.o \ ++ selection.o \ ++ serialio.o \ ++ synth.o \ ++ thread.o \ ++ varhandlers.o +--- a/drivers/staging/speakup/Kconfig 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/Kconfig 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,168 @@ ++menu "Speakup console speech" ++ ++config SPEAKUP ++ depends on VT ++ tristate "Speakup core" ++ ---help--- ++ This is the Speakup screen reader. Think of it as a ++ video console for blind people. If built in to the ++ kernel, it can speak everything on the text console from ++ boot up to shutdown. For more information on Speakup, ++ point your browser at http://www.linux-speakup.org/. ++ There is also a mailing list at the above url that you ++ can subscribe to. ++ ++ Supported synthesizers are accent sa, accent pc, ++ appollo II., Auddapter, Braille 'n Speak, Dectalk ++ external (old), Dectalk PC (full length isa board), ++ Dectalk express, Doubletalk, Doubletalk LT or ++ Litetalk, Keynote Gold internal PC, software ++ synthesizers, Speakout, transport, and a dummy module ++ that can be used with a plain text terminal. ++ ++ Speakup can either be built in or compiled as a module ++ by answering y or m. If you answer y here, then you ++ must answer either y or m to at least one of the ++ synthesizer drivers below. If you answer m here, then ++ the synthesizer drivers below can only be built as ++ modules. ++ ++ These drivers are not standalone drivers, but must be ++ used in conjunction with Speakup. Think of them as ++ video cards for blind people. ++ ++ ++ If you are not a blind person, or don't have access to ++ one of the listed synthesizers, you should say n. ++ ++if SPEAKUP ++config SPEAKUP_SYNTH_ACNTSA ++ tristate "Accent SA synthesizer support" ++ ---help--- ++ This is the Speakup driver for the Accent SA ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_ACNTPC ++ tristate "Accent PC synthesizer support" ++ ---help--- ++ This is the Speakup driver for the accent pc ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_APOLLO ++ tristate "Apollo II synthesizer support" ++ ---help--- ++ This is the Speakup driver for the Apollo II ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_AUDPTR ++ tristate "Audapter synthesizer support" ++ ---help--- ++ This is the Speakup driver for the Audapter synthesizer. ++ You can say y to build it into the kernel, or m to ++ build it as a module. See the configuration help on the ++ Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_BNS ++ tristate "Braille 'n' Speak synthesizer support" ++ ---help--- ++ This is the Speakup driver for the Braille 'n' Speak ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_DECTLK ++ tristate "DECtalk Express synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the DecTalk Express ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_DECEXT ++ tristate "DECtalk External (old) synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the DecTalk External ++ (old) synthesizer. You can say y to build it into the ++ kernel, or m to build it as a module. See the ++ configuration help on the Speakup choice above for more ++ info. ++ ++config SPEAKUP_SYNTH_DTLK ++ tristate "DoubleTalk PC synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the internal DoubleTalk ++ PC synthesizer. You can say y to build it into the ++ kernel, or m to build it as a module. See the ++ configuration help on the Speakup choice above for more ++ info. ++ ++config SPEAKUP_SYNTH_KEYPC ++ tristate "Keynote Gold PC synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the Keynote Gold ++ PC synthesizer. You can say y to build it into the ++ kernel, or m to build it as a module. See the ++ configuration help on the Speakup choice above for more ++ info. ++ ++config SPEAKUP_SYNTH_LTLK ++ tristate "DoubleTalk LT/LiteTalk synthesizer support" ++---help--- ++ ++ This is the Speakup driver for the LiteTalk/DoubleTalk ++ LT synthesizer. You can say y to build it into the ++ kernel, or m to build it as a module. See the ++ configuration help on the Speakup choice above for more ++ info. ++ ++config SPEAKUP_SYNTH_SOFT ++ tristate "Userspace software synthesizer support" ++ ---help--- ++ ++ This is the software synthesizer device node. It will ++ register a device /dev/softsynth which midware programs ++ and speech daemons may open and read to provide kernel ++ output to software synths such as espeak, festival, ++ flite and so forth. You can select 'y' or 'm' to have ++ it built-in to the kernel or loaded as a module. ++ ++config SPEAKUP_SYNTH_SPKOUT ++ tristate "Speak Out synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the Speakout synthesizer. ++ You can say y to build it into the kernel, or m to ++ build it as a module. See the configuration help on the ++ Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_TXPRT ++ tristate "Transport synthesizer support" ++ ---help--- ++ ++ This is the Speakup driver for the Transport ++ synthesizer. You can say y to build it into the kernel, ++ or m to build it as a module. See the configuration ++ help on the Speakup choice above for more info. ++ ++config SPEAKUP_SYNTH_DUMMY ++ tristate "Dummy synthesizer driver (for testing)" ++ ---help--- ++ ++ This is a dummy Speakup driver for plugging a mere serial ++ terminal. This is handy if you want to test speakup but ++ don't have the hardware. You can say y to build it into ++ the kernel, or m to build it as a module. See the ++ configuration help on the Speakup choice above for more info. ++ ++endif # SPEAKUP ++endmenu +--- a/drivers/staging/speakup/keyhelp.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/keyhelp.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,212 @@ ++/* speakup_keyhelp.c ++ help module for speakup ++ ++ written by David Borowski. ++ ++ Copyright (C) 2003 David Borowski. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define MAXFUNCS 130 ++#define MAXKEYS 256 ++static const int num_key_names = MSG_KEYNAMES_END - MSG_KEYNAMES_START + 1; ++static u_short key_offsets[MAXFUNCS], key_data[MAXKEYS]; ++static u_short masks[] = { 32, 16, 8, 4, 2, 1 }; ++ ++static short letter_offsets[26] = ++{ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1, -1, -1, -1, -1, -1, -1, ++ -1, -1 }; ++ ++static u_char funcvals[] = { ++ ATTRIB_BLEEP_DEC, ATTRIB_BLEEP_INC, BLEEPS_DEC, BLEEPS_INC, ++ SAY_FIRST_CHAR, SAY_LAST_CHAR, SAY_CHAR, SAY_CHAR_NUM, ++ SAY_NEXT_CHAR, SAY_PHONETIC_CHAR, SAY_PREV_CHAR, SPEAKUP_PARKED, ++ SPEAKUP_CUT, EDIT_DELIM, EDIT_EXNUM, EDIT_MOST, ++ EDIT_REPEAT, EDIT_SOME, SPEAKUP_GOTO, BOTTOM_EDGE, ++ LEFT_EDGE, RIGHT_EDGE, TOP_EDGE, SPEAKUP_HELP, ++ SAY_LINE, SAY_NEXT_LINE, SAY_PREV_LINE, SAY_LINE_INDENT, ++ SPEAKUP_PASTE, PITCH_DEC, PITCH_INC, PUNCT_DEC, ++ PUNCT_INC, PUNC_LEVEL_DEC, PUNC_LEVEL_INC, SPEAKUP_QUIET, ++ RATE_DEC, RATE_INC, READING_PUNC_DEC, READING_PUNC_INC, ++ SAY_ATTRIBUTES, SAY_FROM_LEFT, SAY_FROM_TOP, SAY_POSITION, ++ SAY_SCREEN, SAY_TO_BOTTOM, SAY_TO_RIGHT, SPK_KEY, ++ SPK_LOCK, SPEAKUP_OFF, SPEECH_KILL, SPELL_DELAY_DEC, ++ SPELL_DELAY_INC, SPELL_WORD, SPELL_PHONETIC, TONE_DEC, ++ TONE_INC, VOICE_DEC, VOICE_INC, VOL_DEC, ++ VOL_INC, CLEAR_WIN, SAY_WIN, SET_WIN, ++ ENABLE_WIN, SAY_WORD, SAY_NEXT_WORD, SAY_PREV_WORD, 0 ++}; ++ ++static u_char *state_tbl; ++static int cur_item, nstates; ++ ++static void build_key_data(void) ++{ ++ u_char *kp, counters[MAXFUNCS], ch, ch1; ++ u_short *p_key = key_data, key; ++ int i, offset = 1; ++ nstates = (int)(state_tbl[-1]); ++ memset(counters, 0, sizeof(counters)); ++ memset(key_offsets, 0, sizeof(key_offsets)); ++ kp = state_tbl + nstates + 1; ++ while (*kp++) { ++ /* count occurrances of each function */ ++ for (i = 0; i < nstates; i++, kp++) { ++ if (!*kp) ++ continue; ++ if ((state_tbl[i]&16) != 0 && *kp == SPK_KEY) ++ continue; ++ counters[*kp]++; ++ } ++ } ++ for (i = 0; i < MAXFUNCS; i++) { ++ if (counters[i] == 0) ++ continue; ++ key_offsets[i] = offset; ++ offset += (counters[i]+1); ++ if (offset >= MAXKEYS) ++ break; ++ } ++/* leave counters set so high keycodes come first. ++ this is done so num pad and other extended keys maps are spoken before ++ the alpha with speakup type mapping. */ ++ kp = state_tbl + nstates + 1; ++ while ((ch = *kp++)) { ++ for (i = 0; i < nstates; i++) { ++ ch1 = *kp++; ++ if (!ch1) ++ continue; ++ if ((state_tbl[i]&16) != 0 && ch1 == SPK_KEY) ++ continue; ++ key = (state_tbl[i] << 8) + ch; ++ counters[ch1]--; ++ offset = key_offsets[ch1]; ++ if (!offset) ++ continue; ++ p_key = key_data + offset + counters[ch1]; ++ *p_key = key; ++ } ++ } ++} ++ ++static void say_key(int key) ++{ ++ int i, state = key >> 8; ++ key &= 0xff; ++ for (i = 0; i < 6; i++) { ++ if (state & masks[i]) ++ synth_printf(" %s", msg_get(MSG_STATES_START + i)); ++ } ++ if ((key > 0) && (key <= num_key_names)) ++ synth_printf(" %s\n", msg_get(MSG_KEYNAMES_START + (key - 1))); ++} ++ ++static int help_init(void) ++{ ++ char start = SPACE; ++ int i; ++ int num_funcs = MSG_FUNCNAMES_END - MSG_FUNCNAMES_START + 1; ++state_tbl = our_keys[0]+SHIFT_TBL_SIZE+2; ++ for (i = 0; i < num_funcs; i++) { ++ char *cur_funcname = msg_get(MSG_FUNCNAMES_START + i); ++ if (start == *cur_funcname) ++ continue; ++ start = *cur_funcname; ++ letter_offsets[(start&31)-1] = i; ++ } ++ return 0; ++} ++ ++int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key) ++{ ++ int i, n; ++ char *name; ++ u_char func, *kp; ++ u_short *p_keys, val; ++ if (letter_offsets[0] == -1) ++ help_init(); ++ if (type == KT_LATIN) { ++ if (ch == SPACE) { ++ special_handler = NULL; ++ synth_printf("%s\n", msg_get(MSG_LEAVING_HELP)); ++ return 1; ++ } ++ ch |= 32; /* lower case */ ++ if (ch < 'a' || ch > 'z') ++ return -1; ++ if (letter_offsets[ch-'a'] == -1) { ++ synth_printf(msg_get(MSG_NO_COMMAND), ch); ++ synth_printf("\n"); ++ return 1; ++ } ++ cur_item = letter_offsets[ch-'a']; ++ } else if (type == KT_CUR) { ++ if (ch == 0 && (cur_item + 1) <= MSG_FUNCNAMES_END) ++ cur_item++; ++ else if (ch == 3 && cur_item > 0) ++ cur_item--; ++ else ++ return -1; ++ } else if (type == KT_SPKUP && ch == SPEAKUP_HELP && !special_handler) { ++ special_handler = handle_help; ++ synth_printf("%s\n", msg_get(MSG_HELP_INFO)); ++ build_key_data(); /* rebuild each time in case new mapping */ ++ return 1; ++ } else { ++ name = NULL; ++ if ((type != KT_SPKUP) && (key > 0) && (key <= num_key_names)) { ++ synth_printf("%s\n", msg_get(MSG_KEYNAMES_START + key-1)); ++ return 1; ++ } ++ for (i = 0; funcvals[i] != 0 && !name; i++) { ++ if (ch == funcvals[i]) ++ name = msg_get(MSG_FUNCNAMES_START + i); ++ } ++ if (!name) ++ return -1; ++ kp = our_keys[key]+1; ++ for (i = 0; i < nstates; i++) { ++ if (ch == kp[i]) ++ break; ++ } ++ key += (state_tbl[i] << 8); ++ say_key(key); ++ synth_printf(msg_get(MSG_KEYDESC), name); ++ synth_printf("\n"); ++ return 1; ++ } ++ name = msg_get(MSG_FUNCNAMES_START + cur_item); ++ func = funcvals[cur_item]; ++ synth_printf("%s", name); ++ if (key_offsets[func] == 0) { ++ synth_printf(" %s\n", msg_get(MSG_IS_UNASSIGNED)); ++ return 1; ++ } ++ p_keys = key_data + key_offsets[func]; ++ for (n = 0; p_keys[n]; n++) { ++ val = p_keys[n]; ++ if (n > 0) ++ synth_printf("%s ", msg_get(MSG_DISJUNCTION)); ++ say_key(val); ++ } ++ return 1; ++} +--- a/drivers/staging/speakup/kobjects.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/kobjects.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,986 @@ ++/* ++ * Speakup kobject implementation ++ * ++ * Copyright (C) 2009 William Hubbs ++ * ++ * This code is based on kobject-example.c, which came with linux 2.6.x. ++ * ++ * Copyright (C) 2004-2007 Greg Kroah-Hartman ++ * Copyright (C) 2007 Novell Inc. ++ * ++ * Released under the GPL version 2 only. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "speakup.h" ++#include "spk_priv.h" ++ ++/* ++ * This is called when a user reads the characters or chartab sys file. ++ */ ++static ssize_t chars_chartab_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ int i; ++ int len = 0; ++ char *cp; ++ char *buf_pointer = buf; ++ size_t bufsize = PAGE_SIZE; ++ unsigned long flags; ++ ++ spk_lock(flags); ++ *buf_pointer = '\0'; ++ for (i = 0; i < 256; i++) { ++ if (bufsize <= 1) ++ break; ++ if (strcmp("characters", attr->attr.name) == 0) { ++ len = scnprintf(buf_pointer, bufsize, "%d\t%s\n", ++ i, characters[i]); ++ } else { /* show chartab entry */ ++ if (IS_TYPE(i, B_CTL)) ++ cp = "B_CTL"; ++ else if (IS_TYPE(i, WDLM)) ++ cp = "WDLM"; ++ else if (IS_TYPE(i, A_PUNC)) ++ cp = "A_PUNC"; ++ else if (IS_TYPE(i, PUNC)) ++ cp = "PUNC"; ++ else if (IS_TYPE(i, NUM)) ++ cp = "NUM"; ++ else if (IS_TYPE(i, A_CAP)) ++ cp = "A_CAP"; ++ else if (IS_TYPE(i, ALPHA)) ++ cp = "ALPHA"; ++ else if (IS_TYPE(i, B_CAPSYM)) ++ cp = "B_CAPSYM"; ++ else if (IS_TYPE(i, B_SYM)) ++ cp = "B_SYM"; ++ else ++ cp = "0"; ++ len = ++ scnprintf(buf_pointer, bufsize, "%d\t%s\n", i, cp); ++ } ++ bufsize -= len; ++ buf_pointer += len; ++ } ++ spk_unlock(flags); ++ return buf_pointer - buf; ++} ++ ++/* ++ * Print informational messages or warnings after updating ++ * character descriptions or chartab entries. ++ */ ++static void report_char_chartab_status(int reset, int received, int used, ++ int rejected, int do_characters) ++{ ++ char *object_type[] = { ++ "character class entries", ++ "character descriptions", ++ }; ++ int len; ++ char buf[80]; ++ ++ if (reset) { ++ pr_info("%s reset to defaults\n", object_type[do_characters]); ++ } else if (received ) { ++ len = snprintf(buf, sizeof(buf), ++ " updated %d of %d %s\n", ++ used, received, object_type[do_characters]); ++ if (rejected) ++ snprintf(buf + (len - 1), sizeof(buf) - (len - 1), ++ " with %d reject%s\n", ++ rejected, rejected > 1 ? "s" : ""); ++ printk(buf); ++ } ++} ++ ++/* ++ * This is called when a user changes the characters or chartab parameters. ++ */ ++static ssize_t chars_chartab_store(struct kobject *kobj, ++ struct kobj_attribute *attr, const char *buf, size_t count) ++{ ++ char *cp = (char *) buf; ++ char *end = cp + count; /* the null at the end of the buffer */ ++ char *linefeed = NULL; ++ char keyword[MAX_DESC_LEN + 1]; ++ char *outptr = NULL; /* Will hold keyword or desc. */ ++ char *temp = NULL; ++ char *desc = NULL; ++ ssize_t retval = count; ++ unsigned long flags; ++ unsigned long index = 0; ++ int charclass = 0; ++ int received = 0; ++ int used = 0; ++ int rejected = 0; ++ int reset = 0; ++ int do_characters = !strcmp(attr->attr.name, "characters"); ++ size_t desc_length = 0; ++ int i; ++ ++ spk_lock(flags); ++ while (cp < end) { ++ ++ while ((cp < end) && (*cp == ' ' || *cp == '\t')) ++ cp++; ++ ++ if (cp == end) ++ break; ++ if ((*cp == '\n') || strchr("dDrR", *cp)) { ++ reset = 1; ++ break; ++ } ++ received++; ++ ++ linefeed = strchr(cp, '\n'); ++ if (!linefeed) { ++ rejected++; ++ break; ++ } ++ ++ if (! isdigit(*cp)) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ ++ index = simple_strtoul(cp, &temp, 10); ++ if (index > 255) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ ++ while ((temp < linefeed) && (*temp == ' ' || *temp == '\t')) ++ temp++; ++ ++ desc_length = linefeed - temp; ++ if (desc_length > MAX_DESC_LEN) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ if (do_characters) { ++ desc = kmalloc(desc_length + 1, GFP_ATOMIC); ++ if (! desc) { ++ retval = -ENOMEM; ++ reset = 1; /* just reset on error. */ ++ break; ++ } ++ outptr = desc; ++ } else { ++ outptr = keyword; ++ } ++ ++ for (i = 0; i < desc_length; i++) ++ outptr[i] = temp[i]; ++ outptr[desc_length] = '\0'; ++ ++ if (do_characters) { ++ if (characters[index] != default_chars[index]) ++ kfree(characters[index]); ++ characters[index] = desc; ++ used++; ++ } else { ++ charclass = chartab_get_value(keyword); ++ if (charclass == 0) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ if (charclass != spk_chartab[index]) { ++ spk_chartab[index] = charclass; ++ used++; ++ } ++ } ++ cp = linefeed + 1; ++ } ++ ++ if (reset) { ++ if (do_characters) ++ reset_default_chars(); ++ else ++ reset_default_chartab(); ++ } ++ ++ spk_unlock(flags); ++ report_char_chartab_status(reset, received, used, rejected, do_characters); ++ return retval; ++} ++ ++/* ++ * This is called when a user reads the keymap parameter. ++ */ ++static ssize_t keymap_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ char *cp = buf; ++ int i; ++ int n; ++ int num_keys; ++ int nstates; ++ u_char *cp1; ++ u_char ch; ++ unsigned long flags; ++ spk_lock(flags); ++ cp1 = key_buf + SHIFT_TBL_SIZE; ++ num_keys = (int)(*cp1); ++ nstates = (int)cp1[1]; ++ cp += sprintf(cp, "%d, %d, %d,\n", KEY_MAP_VER, num_keys, nstates); ++ cp1 += 2; /* now pointing at shift states */ ++/* dump num_keys+1 as first row is shift states + flags, ++ each subsequent row is key + states */ ++ for (n = 0; n <= num_keys; n++) { ++ for (i = 0; i <= nstates; i++) { ++ ch = *cp1++; ++ cp += sprintf(cp, "%d,", (int)ch); ++ *cp++ = (i < nstates) ? SPACE : '\n'; ++ } ++ } ++ cp += sprintf(cp, "0, %d\n", KEY_MAP_VER); ++ spk_unlock(flags); ++ return (int)(cp-buf); ++} ++ ++/* ++ * This is called when a user changes the keymap parameter. ++ */ ++static ssize_t keymap_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int i; ++ ssize_t ret = count; ++ char *in_buff = NULL; ++ char *cp; ++ u_char *cp1; ++ unsigned long flags; ++ ++ spk_lock(flags); ++ in_buff = kmalloc(count + 1, GFP_ATOMIC); ++ if (! in_buff) { ++ spk_unlock(flags); ++ return -ENOMEM; ++ } ++ memcpy(in_buff, buf, count + 1); ++ if (strchr("dDrR", *in_buff)) { ++ set_key_info(key_defaults, key_buf); ++ pr_info("keymap set to default values\n"); ++ kfree(in_buff); ++ spk_unlock(flags); ++ return count; ++ } ++ if (in_buff[count - 1] == '\n') ++ in_buff[count - 1] = '\0'; ++ cp = in_buff; ++ cp1 = (u_char *)in_buff; ++ for (i = 0; i < 3; i++) { ++ cp = s2uchar(cp, cp1); ++ cp1++; ++ } ++ i = (int)cp1[-2]+1; ++ i *= (int)cp1[-1]+1; ++ i += 2; /* 0 and last map ver */ ++ if (cp1[-3] != KEY_MAP_VER || cp1[-1] > 10 || ++ i+SHIFT_TBL_SIZE+4 >= sizeof(key_buf)) { ++ pr_warn("i %d %d %d %d\n", i, ++ (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]); ++ kfree(in_buff); ++ spk_unlock(flags); ++ return -EINVAL; ++ } ++ while (--i >= 0) { ++ cp = s2uchar(cp, cp1); ++ cp1++; ++ if (!(*cp)) ++ break; ++ } ++ if (i != 0 || cp1[-1] != KEY_MAP_VER || cp1[-2] != 0) { ++ ret = -EINVAL; ++ pr_warn("end %d %d %d %d\n", i, ++ (int)cp1[-3], (int)cp1[-2], (int)cp1[-1]); ++ } else { ++ if (set_key_info(in_buff, key_buf)) { ++ set_key_info(key_defaults, key_buf); ++ ret = -EINVAL; ++ pr_warn("set key failed\n"); ++ } ++ } ++ kfree(in_buff); ++ spk_unlock(flags); ++ return ret; ++} ++ ++/* ++ * This is called when a user changes the value of the silent parameter. ++ */ ++static ssize_t silent_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int len; ++ struct vc_data *vc = vc_cons[fg_console].d; ++ char ch = 0; ++ char shut; ++ unsigned long flags; ++ ++ len = strlen(buf); ++ if (len > 0 || len < 3) { ++ ch = buf[0]; ++ if (ch == '\n') ++ ch = '0'; ++ } ++ if (ch < '0' || ch > '7') { ++ pr_warn("silent value '%c' not in range (0,7)\n", ch); ++ return -EINVAL; ++ } ++ spk_lock(flags); ++ if (ch&2) { ++ shut = 1; ++ do_flush(); ++ } else { ++ shut = 0; ++ } ++ if (ch&4) ++ shut |= 0x40; ++ if (ch&1) ++ spk_shut_up |= shut; ++ else ++ spk_shut_up &= ~shut; ++ spk_unlock(flags); ++ return count; ++} ++ ++/* ++ * This is called when a user reads the synth setting. ++ */ ++static ssize_t synth_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ int rv; ++ ++ if (synth == NULL) ++ rv = sprintf(buf, "%s\n", "none"); ++ else ++ rv = sprintf(buf, "%s\n", synth->name); ++ return rv; ++} ++ ++/* ++ * This is called when a user requests to change synthesizers. ++ */ ++static ssize_t synth_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int len; ++ char new_synth_name[10]; ++ ++ len = strlen(buf); ++ if (len < 2 || len > 9) ++ return -EINVAL; ++ strncpy(new_synth_name, buf, len); ++ if (new_synth_name[len - 1] == '\n') ++ len--; ++ new_synth_name[len] = '\0'; ++ strlwr(new_synth_name); ++ if ((synth != NULL) && (!strcmp(new_synth_name, synth->name))) { ++ pr_warn("%s already in use\n", new_synth_name); ++ } else if (synth_init(new_synth_name) != 0) { ++ pr_warn("failed to init synth %s\n", new_synth_name); ++ return -ENODEV; ++ } ++ return count; ++} ++ ++/* ++ * This is called when text is sent to the synth via the synth_direct file. ++ */ ++static ssize_t synth_direct_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ u_char tmp[256]; ++ int len; ++ int bytes; ++ const char *ptr = buf; ++ ++ if (! synth) ++ return -EPERM; ++ ++ len = strlen(buf); ++ while (len > 0) { ++ bytes = min_t(size_t, len, 250); ++ strncpy(tmp, ptr, bytes); ++ tmp[bytes] = '\0'; ++ xlate(tmp); ++ synth_printf("%s", tmp); ++ ptr += bytes; ++ len -= bytes; ++ } ++ return count; ++} ++ ++/* ++ * This function is called when a user reads the version. ++ */ ++static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ char *cp; ++ ++ cp = buf; ++ cp += sprintf(cp, "Speakup version %s\n", SPEAKUP_VERSION); ++ if (synth) ++ cp += sprintf(cp, "%s synthesizer driver version %s\n", ++ synth->name, synth->version); ++ return cp - buf; ++} ++ ++/* ++ * This is called when a user reads the punctuation settings. ++ */ ++static ssize_t punc_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ int i; ++ char *cp = buf; ++ struct st_var_header *p_header; ++ struct punc_var_t *var; ++ struct st_bits_data *pb; ++ short mask; ++ unsigned long flags; ++ ++ p_header = var_header_by_name(attr->attr.name); ++ if (p_header == NULL) { ++ pr_warn("p_header is null, attr->attr.name is %s\n", attr->attr.name); ++ return -EINVAL; ++ } ++ ++ var = get_punc_var(p_header->var_id); ++ if (var == NULL) { ++ pr_warn("var is null, p_header->var_id is %i\n", ++ p_header->var_id); ++ return -EINVAL; ++ } ++ ++ spk_lock(flags); ++ pb = (struct st_bits_data *) &punc_info[var->value]; ++ mask = pb->mask; ++ for (i = 33; i < 128; i++) { ++ if (!(spk_chartab[i]&mask)) ++ continue; ++ *cp++ = (char)i; ++ } ++ spk_unlock(flags); ++ return cp-buf; ++} ++ ++/* ++ * This is called when a user changes the punctuation settings. ++ */ ++static ssize_t punc_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ int x; ++ struct st_var_header *p_header; ++ struct punc_var_t *var; ++ char punc_buf[100]; ++ unsigned long flags; ++ ++ x = strlen(buf); ++ if (x < 1 || x > 99) ++ return -EINVAL; ++ ++ p_header = var_header_by_name(attr->attr.name); ++ if (p_header == NULL) { ++ pr_warn("p_header is null, attr->attr.name is %s\n", attr->attr.name); ++ return -EINVAL; ++ } ++ ++ var = get_punc_var(p_header->var_id); ++ if (var == NULL) { ++ pr_warn("var is null, p_header->var_id is %i\n", ++ p_header->var_id); ++ return -EINVAL; ++ } ++ ++ strncpy(punc_buf, buf, x); ++ ++ while (x && punc_buf[x - 1] == '\n') ++ x--; ++ punc_buf[x] = '\0'; ++ ++ spk_lock(flags); ++ ++ if (*punc_buf == 'd' || *punc_buf == 'r') ++ x = set_mask_bits(0, var->value, 3); ++ else ++ x = set_mask_bits(punc_buf, var->value, 3); ++ ++ spk_unlock(flags); ++ return count; ++} ++ ++/* ++ * This function is called when a user reads one of the variable parameters. ++ */ ++ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf) ++{ ++ int rv = 0; ++ struct st_var_header *param; ++ struct var_t *var; ++ char *cp1; ++ char *cp; ++ char ch; ++ unsigned long flags; ++ ++ param = var_header_by_name(attr->attr.name); ++ if (param == NULL) ++ return -EINVAL; ++ ++ spk_lock(flags); ++ var = (struct var_t *) param->data; ++ switch (param->var_type) { ++ case VAR_NUM: ++ case VAR_TIME: ++ if (var) ++ rv = sprintf(buf, "%i\n", var->u.n.value); ++ else ++ rv = sprintf(buf, "0\n"); ++ break; ++ case VAR_STRING: ++ if (var) { ++ cp1 = buf; ++ *cp1++ = '"'; ++ for (cp = (char *)param->p_val; (ch = *cp); cp++) { ++ if (ch >= ' ' && ch < '~') ++ *cp1++ = ch; ++ else ++ cp1 += sprintf(cp1, "\\""x%02x", ch); ++ } ++ *cp1++ = '"'; ++ *cp1++ = '\n'; ++ *cp1 = '\0'; ++ rv = cp1-buf; ++ } else { ++ rv = sprintf(buf, "\"\"\n"); ++ } ++ break; ++ default: ++ rv = sprintf(buf, "Bad parameter %s, type %i\n", ++ param->name, param->var_type); ++ break; ++ } ++ spk_unlock(flags); ++ return rv; ++} ++EXPORT_SYMBOL_GPL(spk_var_show); ++ ++/* ++ * This function is called when a user echos a value to one of the ++ * variable parameters. ++ */ ++ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct st_var_header *param; ++ int ret; ++ int len; ++ char *cp; ++ struct var_t *var_data; ++ int value; ++ unsigned long flags; ++ ++ param = var_header_by_name(attr->attr.name); ++ if (param == NULL) ++ return -EINVAL; ++ if (param->data == NULL) ++ return 0; ++ ret = 0; ++ cp = xlate((char *) buf); ++ ++ spk_lock(flags); ++ switch (param->var_type) { ++ case VAR_NUM: ++ case VAR_TIME: ++ if (*cp == 'd' || *cp == 'r' || *cp == '\0') ++ len = E_DEFAULT; ++ else if (*cp == '+' || *cp == '-') ++ len = E_INC; ++ else ++ len = E_SET; ++ speakup_s2i(cp, &value); ++ ret = set_num_var(value, param, len); ++ if (ret == E_RANGE) { ++ var_data = param->data; ++ pr_warn("value for %s out of range, expect %d to %d\n", ++ attr->attr.name, ++ var_data->u.n.low, var_data->u.n.high); ++ } ++ break; ++ case VAR_STRING: ++ len = strlen(buf); ++ if ((len >= 1) && (buf[len - 1] == '\n')) ++ --len; ++ if ((len >= 2) && (buf[0] == '"') && (buf[len - 1] == '"')) { ++ ++buf; ++ len -= 2; ++ } ++ cp = (char *) buf; ++ cp[len] = '\0'; ++ ret = set_string_var(buf, param, len); ++ if (ret == E_TOOLONG) ++ pr_warn("value too long for %s\n", ++ attr->attr.name); ++ break; ++ default: ++ pr_warn("%s unknown type %d\n", ++ param->name, (int)param->var_type); ++ break; ++ } ++ spk_unlock(flags); ++ ++ if (ret == SET_DEFAULT) ++ pr_info("%s reset to default value\n", attr->attr.name); ++ return count; ++} ++EXPORT_SYMBOL_GPL(spk_var_store); ++ ++/* ++ * Functions for reading and writing lists of i18n messages. Incomplete. ++ */ ++ ++static ssize_t message_show_helper(char *buf, enum msg_index_t first, ++ enum msg_index_t last) ++{ ++ size_t bufsize = PAGE_SIZE; ++ char *buf_pointer = buf; ++ int printed; ++ enum msg_index_t cursor; ++ int index = 0; ++ *buf_pointer = '\0'; /* buf_pointer always looking at a NUL byte. */ ++ ++ for (cursor = first; cursor <= last; cursor++, index++) { ++ if (bufsize <= 1) ++ break; ++ printed = scnprintf(buf_pointer, bufsize, "%d\t%s\n", ++ index, msg_get(cursor)); ++ buf_pointer += printed; ++ bufsize -= printed; ++ } ++ ++ return buf_pointer - buf; ++} ++ ++static void report_msg_status(int reset, int received, int used, ++ int rejected, char *groupname) ++{ ++ int len; ++ char buf[160]; ++ ++ if (reset) { ++ pr_info("i18n messages from group %s reset to defaults\n", ++ groupname); ++ } else if (received ) { ++ len = snprintf(buf, sizeof(buf), ++ " updated %d of %d i18n messages from group %s\n", ++ used, received, groupname); ++ if (rejected) ++ snprintf(buf + (len - 1), sizeof(buf) - (len - 1), ++ " with %d reject%s\n", ++ rejected, rejected > 1 ? "s" : ""); ++ printk(buf); ++ } ++} ++ ++static ssize_t message_store_helper(const char *buf, size_t count, ++ struct msg_group_t *group) ++{ ++ char *cp = (char *) buf; ++ char *end = cp + count; ++ char *linefeed = NULL; ++ char *temp = NULL; ++ ssize_t msg_stored = 0; ++ ssize_t retval = count; ++ size_t desc_length = 0; ++ unsigned long index = 0; ++ int received = 0; ++ int used = 0; ++ int rejected = 0; ++ int reset = 0; ++ enum msg_index_t firstmessage = group->start; ++ enum msg_index_t lastmessage = group->end; ++ enum msg_index_t curmessage; ++ ++ while (cp < end) { ++ ++ while ((cp < end) && (*cp == ' ' || *cp == '\t')) ++ cp++; ++ ++ if (cp == end) ++ break; ++ if (strchr("dDrR", *cp)) { ++ reset = 1; ++ break; ++ } ++ received++; ++ ++ linefeed = strchr(cp, '\n'); ++ if (!linefeed) { ++ rejected++; ++ break; ++ } ++ ++ if (! isdigit(*cp)) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ ++ index = simple_strtoul(cp, &temp, 10); ++ ++ while ((temp < linefeed) && (*temp == ' ' || *temp == '\t')) ++ temp++; ++ ++ desc_length = linefeed - temp; ++ curmessage = firstmessage + index; ++ ++ /* ++ * Note the check (curmessage < firstmessage). It is not ++ * redundant. Suppose that the user gave us an index ++ * equal to ULONG_MAX - 1. If firstmessage > 1, then ++ * firstmessage + index < firstmessage! ++ */ ++ ++ if ((curmessage < firstmessage) || (curmessage > lastmessage)) { ++ rejected++; ++ cp = linefeed + 1; ++ continue; ++ } ++ ++ msg_stored = msg_set(curmessage, temp, desc_length); ++ if (msg_stored < 0) { ++ retval = msg_stored; ++ if (msg_stored == -ENOMEM) ++ reset = 1; ++ break; ++ } else { ++ used++; ++ } ++ ++ cp = linefeed + 1; ++ } ++ ++ if (reset) ++ reset_msg_group(group); ++ ++ report_msg_status(reset, received, used, rejected, group->name); ++ return retval; ++} ++ ++static ssize_t message_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) ++{ ++ ssize_t retval = 0; ++ struct msg_group_t *group = find_msg_group(attr->attr.name); ++ unsigned long flags; ++ ++ BUG_ON(! group); ++ spk_lock(flags); ++ retval = message_show_helper(buf, group->start, group->end); ++ spk_unlock(flags); ++ return retval; ++} ++ ++static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count) ++{ ++ ssize_t retval = 0; ++ struct msg_group_t *group = find_msg_group(attr->attr.name); ++ ++ BUG_ON(! group); ++ retval = message_store_helper(buf, count, group); ++ return retval; ++} ++ ++/* ++ * Declare the attributes. ++ */ ++static struct kobj_attribute keymap_attribute = ++ __ATTR(keymap, ROOT_W, keymap_show, keymap_store); ++static struct kobj_attribute silent_attribute = ++ __ATTR(silent, USER_W, NULL, silent_store); ++static struct kobj_attribute synth_attribute = ++ __ATTR(synth, USER_RW, synth_show, synth_store); ++static struct kobj_attribute synth_direct_attribute = ++ __ATTR(synth_direct, USER_W, NULL, synth_direct_store); ++static struct kobj_attribute version_attribute = ++ __ATTR_RO(version); ++ ++static struct kobj_attribute delimiters_attribute = ++ __ATTR(delimiters, USER_RW, punc_show, punc_store); ++static struct kobj_attribute ex_num_attribute = ++ __ATTR(ex_num, USER_RW, punc_show, punc_store); ++static struct kobj_attribute punc_all_attribute = ++ __ATTR(punc_all, USER_RW, punc_show, punc_store); ++static struct kobj_attribute punc_most_attribute = ++ __ATTR(punc_most, USER_RW, punc_show, punc_store); ++static struct kobj_attribute punc_some_attribute = ++ __ATTR(punc_some, USER_RW, punc_show, punc_store); ++static struct kobj_attribute repeats_attribute = ++ __ATTR(repeats, USER_RW, punc_show, punc_store); ++ ++static struct kobj_attribute attrib_bleep_attribute = ++ __ATTR(attrib_bleep, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute bell_pos_attribute = ++ __ATTR(bell_pos, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute bleep_time_attribute = ++ __ATTR(bleep_time, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute bleeps_attribute = ++ __ATTR(bleeps, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute cursor_time_attribute = ++ __ATTR(cursor_time, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute key_echo_attribute = ++ __ATTR(key_echo, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute no_interrupt_attribute = ++ __ATTR(no_interrupt, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punc_level_attribute = ++ __ATTR(punc_level, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute reading_punc_attribute = ++ __ATTR(reading_punc, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute say_control_attribute = ++ __ATTR(say_control, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute say_word_ctl_attribute = ++ __ATTR(say_word_ctl, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute spell_delay_attribute = ++ __ATTR(spell_delay, USER_RW, spk_var_show, spk_var_store); ++ ++/* ++ * These attributes are i18n related. ++ */ ++static struct kobj_attribute announcements_attribute = ++ __ATTR(announcements, USER_RW, message_show, message_store); ++static struct kobj_attribute characters_attribute = ++ __ATTR(characters, USER_RW, chars_chartab_show, chars_chartab_store); ++static struct kobj_attribute chartab_attribute = ++ __ATTR(chartab, USER_RW, chars_chartab_show, chars_chartab_store); ++static struct kobj_attribute ctl_keys_attribute = ++ __ATTR(ctl_keys, USER_RW, message_show, message_store); ++static struct kobj_attribute colors_attribute = ++ __ATTR(colors, USER_RW, message_show, message_store); ++static struct kobj_attribute formatted_attribute = ++ __ATTR(formatted, USER_RW, message_show, message_store); ++static struct kobj_attribute function_names_attribute = ++ __ATTR(function_names, USER_RW, message_show, message_store); ++static struct kobj_attribute key_names_attribute = ++ __ATTR(key_names, USER_RW, message_show, message_store); ++static struct kobj_attribute states_attribute = ++ __ATTR(states, USER_RW, message_show, message_store); ++ ++/* ++ * Create groups of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *main_attrs[] = { ++ &keymap_attribute.attr, ++ &silent_attribute.attr, ++ &synth_attribute.attr, ++ &synth_direct_attribute.attr, ++ &version_attribute.attr, ++ &delimiters_attribute.attr, ++ &ex_num_attribute.attr, ++ &punc_all_attribute.attr, ++ &punc_most_attribute.attr, ++ &punc_some_attribute.attr, ++ &repeats_attribute.attr, ++ &attrib_bleep_attribute.attr, ++ &bell_pos_attribute.attr, ++ &bleep_time_attribute.attr, ++ &bleeps_attribute.attr, ++ &cursor_time_attribute.attr, ++ &key_echo_attribute.attr, ++ &no_interrupt_attribute.attr, ++ &punc_level_attribute.attr, ++ &reading_punc_attribute.attr, ++ &say_control_attribute.attr, ++ &say_word_ctl_attribute.attr, ++ &spell_delay_attribute.attr, ++ NULL, ++}; ++ ++static struct attribute *i18n_attrs[] = { ++ &announcements_attribute.attr, ++ &characters_attribute.attr, ++ &chartab_attribute.attr, ++ &ctl_keys_attribute.attr, ++ &colors_attribute.attr, ++ &formatted_attribute.attr, ++ &function_names_attribute.attr, ++ &key_names_attribute.attr, ++ &states_attribute.attr, ++ NULL, ++}; ++ ++/* ++ * An unnamed attribute group will put all of the attributes directly in ++ * the kobject directory. If we specify a name, a subdirectory will be ++ * created for the attributes with the directory being the name of the ++ * attribute group. ++ */ ++static struct attribute_group main_attr_group = { ++ .attrs = main_attrs, ++}; ++ ++static struct attribute_group i18n_attr_group = { ++ .attrs = i18n_attrs, ++ .name = "i18n", ++}; ++ ++static struct kobject *accessibility_kobj; ++struct kobject *speakup_kobj; ++ ++int speakup_kobj_init(void) ++{ ++ int retval; ++ ++ /* ++ * Create a simple kobject with the name of "accessibility", ++ * located under /sys/ ++ * ++ * As this is a simple directory, no uevent will be sent to ++ * userspace. That is why this function should not be used for ++ * any type of dynamic kobjects, where the name and number are ++ * not known ahead of time. ++ */ ++ accessibility_kobj = kobject_create_and_add("accessibility", NULL); ++ if (!accessibility_kobj) ++ return -ENOMEM; ++ ++ speakup_kobj = kobject_create_and_add("speakup", accessibility_kobj); ++ if (!speakup_kobj) { ++ kobject_put(accessibility_kobj); ++ return -ENOMEM; ++ } ++ ++ /* Create the files associated with this kobject */ ++ retval = sysfs_create_group(speakup_kobj, &main_attr_group); ++ if (retval) ++ speakup_kobj_exit(); ++ ++ retval = sysfs_create_group(speakup_kobj, &i18n_attr_group); ++ if (retval) ++ speakup_kobj_exit(); ++ ++ return retval; ++} ++ ++void speakup_kobj_exit(void) ++{ ++ kobject_put(speakup_kobj); ++ kobject_put(accessibility_kobj); ++} +--- a/drivers/staging/speakup/main.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/main.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,2284 @@ ++/* 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. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#include ++#include ++#include ++#include ++#include /* __get_free_page() and friends */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include /* for KT_SHIFT */ ++#include /* for vc_kbd_* and friends */ ++#include ++#include ++ ++#include /* for alloc_bootmem */ ++ ++/* speakup_*_selection */ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include /* 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 "); ++MODULE_AUTHOR("Daniel Drake "); ++MODULE_DESCRIPTION("Speakup console speech"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(SPEAKUP_VERSION); ++ ++char *synth_name; ++module_param_named(synth, synth_name, charp, S_IRUGO); ++module_param_named(quiet, quiet_boot, bool, S_IRUGO); ++ ++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 special_handler; ++ ++short pitch_shift, synth_flags; ++static char buf[256]; ++int attrib_bleep, bleeps, bleep_time = 10; ++int no_intr, spell_delay; ++int key_echo, say_word_ctl; ++int say_ctrl, bell_pos; ++short punc_mask; ++int punc_level, reading_punc; ++char str_caps_start[MAXVARLEN+1] = "\0", str_caps_stop[MAXVARLEN+1] = "\0"; ++const struct st_bits_data punc_info[] = { ++ { "none", "", 0 }, ++ { "some", "/$%&@", SOME }, ++ { "most", "$%&#()=+*/@^<>|\\", MOST }, ++ { "all", "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", PUNC }, ++ { "delimiters", "", B_WDLM }, ++ { "repeats", "()", CH_RPT }, ++ { "extended numeric", "", B_EXNUM }, ++ { "symbols", "", B_SYM }, ++ { 0, 0 } ++}; ++static char mark_cut_flag; ++#define MAX_KEY 160 ++u_char *our_keys[MAX_KEY], *shift_table; ++u_char key_buf[600]; ++const u_char 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; ++typedef void (*k_handler_fn)(struct vc_data *vc, unsigned char value, ++ char up_flag); ++extern k_handler_fn k_handler[16]; ++ ++static void spkup_write(const char *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 *characters[256]; ++ ++char *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, B_SYM, /* 128-135 */ ++B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, /* 136-143 */ ++B_CAPSYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 144-151 */ ++B_SYM, B_SYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 152-159 */ ++WDLM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, /* 160-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; ++static int spk_keydown; ++static u_char spk_lastkey, 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); ++ ++struct notifier_block keyboard_notifier_block = { ++ .notifier_call = keyboard_notifier_call, ++}; ++ ++static int vt_notifier_call(struct notifier_block *, ++ unsigned long code, void *param); ++ ++struct notifier_block vt_notifier_block = { ++ .notifier_call = vt_notifier_call, ++}; ++ ++static unsigned char get_attributes(u16 *pos) ++{ ++ return (u_char)(scr_readw(pos) >> 8); ++} ++ ++static void speakup_date(struct vc_data *vc) ++{ ++ spk_x = spk_cx = vc->vc_x; ++ spk_y = spk_cy = vc->vc_y; ++ spk_pos = spk_cp = vc->vc_pos; ++ spk_old_attr = spk_attr; ++ spk_attr = get_attributes((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 = bleep_time; ++ freq = vals[val%12]; ++ if (val > 11) ++ freq *= (1 << (val/12)); ++ kd_mksound(freq, msecs_to_jiffies(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 != NULL) ++ 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", msg_get(MSG_IAM_ALIVE)); ++ } else { ++ synth_printf("%s\n", 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", msg_get(MSG_HEY_THATS_BETTER)); ++ } else { ++ spk_shut_up |= 0x80; ++ synth_printf("%s\n", 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", msg_get(MSG_UNPARKED)); ++ } else { ++ spk_parked |= 0x80; ++ synth_printf("%s\n", 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; ++ xs = (u_short) spk_x; ++ ys = (u_short) spk_y; ++ spk_sel_cons = vc; ++ synth_printf("%s\n", msg_get(MSG_MARK)); ++ return; ++ } ++ xe = (u_short) spk_x; ++ ye = (u_short) spk_y; ++ mark_cut_flag = 0; ++ synth_printf("%s\n", msg_get(MSG_CUT)); ++ ++ speakup_clear_selection(); ++ 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", msg_get(MSG_MARK_CLEARED)); ++ } else { ++ synth_printf("%s\n", 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 ", msg_get(MSG_BRIGHT)); ++ fg -= 8; ++ } ++ synth_printf("%s", msg_get(MSG_COLORS_START + fg)); ++ if (bg > 7) { ++ synth_printf(" %s ", msg_get(MSG_ON_BLINKING)); ++ bg -= 8; ++ } else ++ synth_printf(" %s ", msg_get(MSG_ON)); ++ synth_printf("%s\n", 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 (bleeps & 1) ++ bleep(spk_y); ++ if ((bleeps & 2) && (msg_id < edge_quiet)) ++ synth_printf("%s\n", msg_get(MSG_EDGE_MSGS_START + msg_id - 1)); ++} ++ ++static void speak_char(u_char ch) ++{ ++ char *cp = characters[ch]; ++ struct var_t *direct = get_var(DIRECT); ++ if (direct && direct->u.n.value) { ++ if (IS_CHAR(ch, B_CAP)) { ++ pitch_shift++; ++ synth_printf("%s", str_caps_start); ++ } ++ synth_printf("%c", ch); ++ if (IS_CHAR(ch, B_CAP)) ++ synth_printf("%s", str_caps_stop); ++ return; ++ } ++ if (cp == NULL) { ++ pr_info("speak_char: cp == NULL!\n"); ++ return; ++ } ++ synth_buffer_add(SPACE); ++ if (IS_CHAR(ch, B_CAP)) { ++ pitch_shift++; ++ synth_printf("%s", str_caps_start); ++ synth_printf("%s", cp); ++ synth_printf("%s", str_caps_stop); ++ } else { ++ if (*cp == '^') { ++ synth_printf("%s", msg_get(MSG_CTRL)); ++ cp++; ++ } ++ synth_printf("%s", cp); ++ } ++ synth_buffer_add(SPACE); ++} ++ ++static u16 get_char(struct vc_data *vc, u16 *pos, u_char *attribs) ++{ ++ u16 ch = ' '; ++ if (vc && pos) { ++ u16 w = scr_readw(pos); ++ u16 c = w & 0xff; ++ ++ if (w & vc->vc_hi_font_mask) ++ c |= 0x100; ++ ++ ch = inverse_translate(vc, c); ++ *attribs = (w & 0xff00) >> 8; ++ } ++ return ch; ++} ++ ++static void say_char(struct vc_data *vc) ++{ ++ u_short ch; ++ spk_old_attr = spk_attr; ++ ch = get_char(vc, (u_short *) spk_pos, &spk_attr); ++ if (spk_attr != spk_old_attr) { ++ if (attrib_bleep & 1) ++ bleep(spk_y); ++ if (attrib_bleep & 2) ++ say_attributes(vc); ++ } ++ speak_char(ch & 0xff); ++} ++ ++static void say_phonetic_char(struct vc_data *vc) ++{ ++ u_short ch; ++ spk_old_attr = spk_attr; ++ ch = get_char(vc, (u_short *) spk_pos, &spk_attr); ++ if (isascii(ch) && isalpha(ch)) { ++ ch &= 0x1f; ++ synth_printf("%s\n", phonetic[--ch]); ++ } else { ++ if (IS_CHAR(ch, B_NUM)) ++ synth_printf("%s ", 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 say_word_ctl is true it will ++ return the word space. If 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; ++ char ch; ++ u_short attr_ch; ++ u_char temp; ++ spk_old_attr = spk_attr; ++ ch = (char) get_char(vc, (u_short *) tmp_pos, &temp); ++ ++/* decided to take out the sayword if on a space (mis-information */ ++ if (say_word_ctl && ch == SPACE) { ++ *buf = '\0'; ++ synth_printf("%s\n", msg_get(MSG_SPACE)); ++ return 0; ++ } else if ((tmpx < vc->vc_cols - 2) ++ && (ch == SPACE || ch == 0 || IS_WDLM(ch)) ++ && ((char) get_char(vc, (u_short *) &tmp_pos+1, &temp) > SPACE)) { ++ tmp_pos += 2; ++ tmpx++; ++ } else ++ while (tmpx > 0) { ++ ch = (char) get_char(vc, (u_short *) tmp_pos - 1, &temp); ++ if ((ch == SPACE || ch == 0 || IS_WDLM(ch)) ++ && ((char) 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 & 0xff; ++ while (tmpx < vc->vc_cols - 1) { ++ tmp_pos += 2; ++ tmpx++; ++ ch = (char) get_char(vc, (u_short *) tmp_pos, &temp); ++ if ((ch == SPACE) || ch == 0 || (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 = punc_mask; ++ if (cnt == 0) ++ return; ++ punc_mask = PUNC; ++ buf[cnt++] = SPACE; ++ spkup_write(buf, cnt); ++ punc_mask = saved_punc_mask; ++} ++ ++static void say_prev_word(struct vc_data *vc) ++{ ++ u_char temp; ++ char 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 = (char) get_char(vc, (u_short *) spk_pos, &temp); ++ if (ch == SPACE || ch == 0) ++ state = 0; ++ else if (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; ++ char 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 = (char) get_char(vc, (u_short *) spk_pos, &temp); ++ if (ch == SPACE || ch == 0) ++ state = 0; ++ else if (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 *delay_str[] = { "", ",", ".", ". .", ". . ." }; ++ char *cp = buf, *str_cap = str_caps_stop; ++ char *cp1, *last_cap = str_caps_stop; ++ u_char ch; ++ if (!get_word(vc)) ++ return; ++ while ((ch = (u_char) *cp)) { ++ if (cp != buf) ++ synth_printf(" %s ", delay_str[spell_delay]); ++ if (IS_CHAR(ch, B_CAP)) { ++ str_cap = str_caps_start; ++ if (*str_caps_stop) ++ pitch_shift++; ++ else /* synth has no pitch */ ++ last_cap = str_caps_stop; ++ } else ++ str_cap = str_caps_stop; ++ if (str_cap != last_cap) { ++ synth_printf("%s", str_cap); ++ last_cap = str_cap; ++ } ++ if (this_speakup_key == SPELL_PHONETIC ++ && (isascii(ch) && isalpha(ch))) { ++ ch &= 31; ++ cp1 = phonetic[--ch]; ++ } else { ++ cp1 = characters[ch]; ++ if (*cp1 == '^') { ++ synth_printf("%s", msg_get(MSG_CTRL)); ++ cp1++; ++ } ++ } ++ synth_printf("%s", cp1); ++ cp++; ++ } ++ if (str_cap != str_caps_stop) ++ synth_printf("%s", 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((u_short *) spk_pos); ++ for (i = 0; i < vc->vc_cols; i++) { ++ buf[i] = (u_char) 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); ++ char *cp; ++ u_short saved_punc_mask = punc_mask; ++ if (i == 0) { ++ synth_printf("%s\n", msg_get(MSG_BLANK)); ++ return; ++ } ++ buf[i++] = '\n'; ++ if (this_speakup_key == SAY_LINE_INDENT) { ++ for (cp = buf; *cp == SPACE; cp++) ++ ; ++ synth_printf("%d, ", (cp - buf) + 1); ++ } ++ punc_mask = punc_masks[reading_punc]; ++ spkup_write(buf, i); ++ 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 = punc_mask; ++ spk_old_attr = spk_attr; ++ spk_attr = get_attributes((u_short *) from); ++ while (from < to) { ++ buf[i++] = (char) 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) ++ punc_mask = punc_info[reading_punc].mask; ++ spkup_write(buf, i); ++ if (read_punc) ++ 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", msg_get(MSG_BLANK)); ++} ++ ++/* Sentence Reading Commands */ ++ ++void synth_insert_next_index(int); ++ ++static int currsentence; ++static int numsentences[2]; ++static char *sentbufend[2]; ++static char *sentmarks[2][10]; ++static int currbuf; ++static int bn; ++static char 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((u_short *) start); ++ ++ while (start < end) { ++ sentbuf[bn][i] = (char) 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", 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); ++ u_char ch; ++ spk_parked |= 0x01; ++ if (len == 0) { ++ synth_printf("%s\n", 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); ++ u_char ch; ++ spk_parked |= 0x01; ++ if (len == 0) { ++ synth_printf("%s\n", 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(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; ++ u_short ch = get_char(vc, (u_short *) spk_pos, &tmp); ++ ch &= 0xff; ++ synth_printf(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 char *in_buf, int count) ++{ ++ static int rep_count = 0; ++ static u_char ch = '\0', old_ch = '\0'; ++ static u_short char_type = 0, last_type = 0; ++ 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 = (u_char)*in_buf++; ++ char_type = spk_chartab[ch]; ++ 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(msg_get(MSG_REPEAT_DESC), ++rep_count); ++ synth_printf(" "); ++ } ++ rep_count = 0; ++ } ++ if (ch == spk_lastkey) { ++ rep_count = 0; ++ if (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_printf("%c", ch); ++ } else if (char_type & B_NUM) { ++ rep_count = 0; ++ synth_printf("%c", ch); ++ } else if (char_type&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 pausesand clear repeat count so if ++ *someone has repeats on you don't get nothing repeated count */ ++ if (ch != old_ch) ++ synth_printf("%c", 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(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(u_long data); ++static DEFINE_TIMER(cursor_timer, cursor_done, 0, 0); ++ ++static void do_handle_shift(struct vc_data *vc, u_char value, char up_flag) ++{ ++ unsigned long flags; ++ if (synth == NULL || up_flag || spk_killed) ++ return; ++ spk_lock(flags); ++ if (cursor_track == read_all_mode) { ++ switch (value) { ++ case KVAL(K_SHIFT): ++ del_timer(&cursor_timer); ++ spk_shut_up &= 0xfe; ++ do_flush(); ++ read_all_doc(vc); ++ break; ++ case KVAL(K_CTRL): ++ del_timer(&cursor_timer); ++ cursor_track = prev_cursor_track; ++ spk_shut_up &= 0xfe; ++ do_flush(); ++ break; ++ } ++ } else { ++ spk_shut_up &= 0xfe; ++ do_flush(); ++ } ++ if (say_ctrl && value < NUM_CTL_LABELS) ++ synth_printf("%s", msg_get(MSG_CTL_START + value)); ++ spk_unlock(flags); ++} ++ ++static void do_handle_latin(struct vc_data *vc, u_char value, char up_flag) ++{ ++ unsigned long flags; ++ spk_lock(flags); ++ if (up_flag) { ++ spk_lastkey = spk_keydown = 0; ++ spk_unlock(flags); ++ return; ++ } ++ if (synth == NULL || spk_killed) { ++ spk_unlock(flags); ++ return; ++ } ++ spk_shut_up &= 0xfe; ++ spk_lastkey = value; ++ spk_keydown++; ++ spk_parked &= 0xfe; ++ if (key_echo == 2 && value >= MINECHOCHAR) ++ speak_char(value); ++ spk_unlock(flags); ++} ++ ++int 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) ++ return -1; ++ num_keys = *cp; ++ states = (int) cp[1]; ++ key_data_len = (states + 1) * (num_keys + 1); ++ if (key_data_len + SHIFT_TBL_SIZE + 4 >= sizeof(key_buf)) ++ return -2; ++ memset(k_buffer, 0, SHIFT_TBL_SIZE); ++ memset(our_keys, 0, sizeof(our_keys)); ++ shift_table = k_buffer; ++ our_keys[0] = 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) ++ return -3; ++ shift_table[ch] = i; ++ } ++ keymap_flags = *cp1++; ++ while ((ch = *cp1)) { ++ if (ch >= MAX_KEY) ++ return -4; ++ 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", msg_get(MSG_CURSOR_MSGS_START + cursor_track)); ++} ++ ++void reset_default_chars(void) ++{ ++ int i; ++ ++ /* First, free any non-default */ ++ for (i = 0; i < 256; i++) { ++ if ((characters[i] != NULL) ++ && (characters[i] != default_chars[i])) ++ kfree(characters[i]); ++ } ++ ++ memcpy(characters, default_chars, sizeof(default_chars)); ++} ++ ++void reset_default_chartab(void) ++{ ++ memcpy(spk_chartab, default_chartab, sizeof(default_chartab)); ++} ++ ++static const struct st_bits_data *pb_edit = NULL; ++ ++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", msg_get(MSG_EDIT_DONE)); ++ 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) ? msg_get(MSG_ON) : msg_get(MSG_OFF)); ++ return 1; ++} ++ ++/* Allocation concurrency is protected by the console semaphore */ ++void speakup_allocate(struct vc_data *vc) ++{ ++ int vc_num; ++ ++ vc_num = vc->vc_num; ++ if (speakup_console[vc_num] == NULL) { ++ speakup_console[vc_num] = kzalloc(sizeof(*speakup_console[0]), ++ GFP_ATOMIC); ++ if (speakup_console[vc_num] == NULL) ++ return; ++ speakup_date(vc); ++ } else if (!spk_parked) ++ speakup_date(vc); ++} ++ ++void speakup_deallocate(struct vc_data *vc) ++{ ++ int vc_num; ++ ++ vc_num = vc->vc_num; ++ if (speakup_console[vc_num] != NULL) { ++ 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; ++ ++void reset_index_count(int); ++void get_index_count(int *, int *); ++/*int synth_supports_indexing(void); */ ++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 v, int command) ++{ ++ del_timer(&cursor_timer); ++ k_handler[KT_CUR](vc, v, 0); ++ k_handler[KT_CUR](vc, v, 1); ++ start_read_all_timer(vc, command); ++} ++ ++static void ++read_all_doc(struct vc_data *vc) ++{ ++ if ((vc->vc_num != fg_console) || synth == NULL || 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; ++ reset_index_count(0); ++ if (get_sentence_buf(vc, 0) == -1) ++ kbd_fakekey2(vc, 0, 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; ++ 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 = 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 */ ++ get_index_count(&indcount, &sentcount); ++ /*printk("%d %d ", indcount, sentcount); */ ++ reset_index_count(sentcount+1); ++ if (indcount == 1) { ++ if (!say_sentence_num(sentcount+1, 0)) { ++ kbd_fakekey2(vc, 0, RA_FIND_NEXT_SENT); ++ return; ++ } ++ synth_insert_next_index(0); ++ } else { ++ sn = 0; ++ if (!say_sentence_num(sentcount+1, 1)) { ++ sn = 1; ++ reset_index_count(sn); ++ } else ++ synth_insert_next_index(0); ++ if (!say_sentence_num(sn, 0)) { ++ kbd_fakekey2(vc, 0, 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, 0, 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, 0, 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: ++ get_index_count(&indcount, &sentcount); ++ if (indcount < 2) ++ kbd_fakekey2(vc, 0, 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; ++ spk_lock(flags); ++ if (cursor_track == read_all_mode) { ++ spk_parked &= 0xfe; ++ if (synth == NULL || up_flag || spk_shut_up) { ++ spk_unlock(flags); ++ return NOTIFY_STOP; ++ } ++ del_timer(&cursor_timer); ++ spk_shut_up &= 0xfe; ++ do_flush(); ++ start_read_all_timer(vc, value+1); ++ spk_unlock(flags); ++ return NOTIFY_STOP; ++ } ++ spk_unlock(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; ++ ++ spk_lock(flags); ++ spk_parked &= 0xfe; ++ if (synth == NULL || up_flag || spk_shut_up || cursor_track == CT_Off) { ++ spk_unlock(flags); ++ return; ++ } ++ spk_shut_up &= 0xfe; ++ if (no_intr) ++ 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->vc_x; ++ old_cursor_y = vc->vc_y; ++ speakup_console[vc->vc_num]->ht.cy = vc->vc_y; ++ cursor_con = vc->vc_num; ++ if (cursor_track == CT_Highlight) ++ reset_highlight_buffers(vc); ++ cursor_timeout = get_var(CURSOR_TIME); ++ mod_timer(&cursor_timer, jiffies + msecs_to_jiffies(cursor_timeout->u.n.value)); ++ spk_unlock(flags); ++} ++ ++static void ++update_color_buffer(struct vc_data *vc , const char *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->vc_x; ++ speakup_console[vc_num]->ht.ry[bi] = vc->vc_y; ++ } ++ while ((hi < COLOR_BUFFER_SIZE) && (i < len)) { ++ if ((ic[i] > 32) && (ic[i] < 127)) { ++ 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(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], tmp; ++ 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]]) { ++ tmp = cptr[i]; ++ cptr[i] = cptr[j]; ++ cptr[j] = tmp; ++ } ++ ++ 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->vc_y-speakup_console[vc_num]->ht.cy; ++ if ((d == 1) || (d == -1)) ++ if (speakup_console[vc_num]->ht.ry[hc] != vc->vc_y) ++ return 0; ++ spk_parked |= 0x01; ++ 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(u_long data) ++{ ++ struct vc_data *vc = vc_cons[cursor_con].d; ++ unsigned long flags; ++ del_timer(&cursor_timer); ++ spk_lock(flags); ++ if (cursor_con != fg_console) { ++ is_cursor = 0; ++ goto out; ++ } ++ speakup_date(vc); ++ if (win_enabled) { ++ if (vc->vc_x >= win_left && vc->vc_x <= win_right && ++ vc->vc_y >= win_top && vc->vc_y <= win_bottom) { ++ spk_keydown = 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 = 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 = is_cursor = 0; ++out: ++ spk_unlock(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 (!spk_trylock(flags)) ++ /* Speakup output, discard */ ++ return; ++ if (!spk_parked) ++ speakup_date(vc); ++ if (spk_shut_up || synth == NULL) { ++ spk_unlock(flags); ++ return; ++ } ++ if (vc->vc_num == fg_console && spk_keydown) { ++ spk_keydown = 0; ++ if (!is_cursor) ++ say_char(vc); ++ } ++ spk_unlock(flags); ++} ++ ++/* called by: vt_notifier_call() */ ++static void speakup_con_write(struct vc_data *vc, const char *str, int len) ++{ ++ unsigned long flags; ++ if ((vc->vc_num != fg_console) || spk_shut_up || synth == NULL) ++ return; ++ if (!spk_trylock(flags)) ++ /* Speakup output, discard */ ++ return; ++ if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1)) ++ bleep(3); ++ if ((is_cursor) || (cursor_track == read_all_mode)) { ++ if (cursor_track == CT_Highlight) ++ update_color_buffer(vc, str, len); ++ spk_unlock(flags); ++ return; ++ } ++ if (win_enabled) { ++ if (vc->vc_x >= win_left && vc->vc_x <= win_right && ++ vc->vc_y >= win_top && vc->vc_y <= win_bottom) { ++ spk_unlock(flags); ++ return; ++ } ++ } ++ ++ spkup_write(str, len); ++ spk_unlock(flags); ++} ++ ++void ++speakup_con_update(struct vc_data *vc) ++{ ++ unsigned long flags; ++ if (speakup_console[vc->vc_num] == NULL || spk_parked) ++ return; ++ if (!spk_trylock(flags)) ++ /* Speakup output, discard */ ++ return; ++ speakup_date(vc); ++ spk_unlock(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 == NULL || up_flag || spk_killed) ++ return; ++ spk_lock(flags); ++ spk_shut_up &= 0xfe; ++ if (no_intr) ++ do_flush(); ++ switch (value) { ++ case KVAL(K_CAPS): ++ label = msg_get(MSG_KEYNAME_CAPSLOCK); ++ on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_CAPSLOCK)); ++ break; ++ case KVAL(K_NUM): ++ label = msg_get(MSG_KEYNAME_NUMLOCK); ++ on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_NUMLOCK)); ++ break; ++ case KVAL(K_HOLD): ++ label = msg_get(MSG_KEYNAME_SCROLLLOCK); ++ on_off = (vc_kbd_led(kbd_table + vc->vc_num, VC_SCROLLOCK)); ++ if (speakup_console[vc->vc_num]) ++ speakup_console[vc->vc_num]->tty_stopped = on_off; ++ break; ++ default: ++ spk_parked &= 0xfe; ++ spk_unlock(flags); ++ return; ++ } ++ if (on_off < 2) ++ synth_printf("%s %s\n", ++ label, msg_get(MSG_STATUS_START + on_off)); ++ spk_unlock(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 = get_var_header(var_id); ++ if (p_header == NULL) ++ return -1; ++ if (p_header->var_type != VAR_NUM) ++ return -1; ++ var_data = p_header->data; ++ if (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", msg_get(MSG_WINDOW_ALREADY_SET)); ++ return; ++ } ++ if (spk_x < win_left || spk_y < win_top) { ++ synth_printf("%s\n", 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), 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), msg_get(MSG_WINDOW_BOUNDARY), ++ (win_start) ? msg_get(MSG_END) : 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 = win_bottom = 0; ++ win_left = win_right = 0; ++ win_start = 0; ++ synth_printf("%s\n", msg_get(MSG_WINDOW_CLEARED)); ++} ++ ++static void ++speakup_win_enable(struct vc_data *vc) ++{ ++ if (win_start < 2) { ++ synth_printf("%s\n", msg_get(MSG_NO_WINDOW)); ++ return; ++ } ++ win_enabled ^= 1; ++ if (win_enabled) ++ synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCED)); ++ else ++ synth_printf("%s\n", msg_get(MSG_WINDOW_SILENCE_DISABLED)); ++} ++ ++static void ++speakup_bits(struct vc_data *vc) ++{ ++ int val = this_speakup_key - (FIRST_EDIT_BITS - 1); ++ if (special_handler != NULL || val < 1 || val > 6) { ++ synth_printf("%s\n", msg_get(MSG_ERROR)); ++ return; ++ } ++ pb_edit = &punc_info[val]; ++ synth_printf(msg_get(MSG_EDIT_PROMPT), pb_edit->name); ++ 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 = "\0\0\0\0\0\0"; ++ static int num = 0; ++ int maxlen, go_pos; ++ char *cp; ++ 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) { ++ if (num == 0) ++ return -1; ++ ch = goto_buf[--num]; ++ goto_buf[num] = '\0'; ++ spkup_write(&ch, 1); ++ return 1; ++ } ++ if (ch < '+' || ch > 'y') ++ goto oops; ++ goto_buf[num++] = ch; ++ goto_buf[num] = '\0'; ++ spkup_write(&ch, 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", msg_get(MSG_GOTO_CANCELED)); ++ goto_buf[num = 0] = '\0'; ++ special_handler = NULL; ++ return 1; ++ } ++ cp = speakup_s2i(goto_buf, &go_pos); ++ goto_pos = (u_long)go_pos; ++ if (*cp == 'x') { ++ if (*goto_buf < '0') ++ goto_pos += spk_x; ++ else ++ goto_pos--; ++ if (goto_pos < 0) ++ goto_pos = 0; ++ 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 ++ goto_pos--; ++ if (goto_pos < 0) ++ goto_pos = 0; ++ if (goto_pos >= vc->vc_rows) ++ goto_pos = vc->vc_rows-1; ++ goto_x = 0; ++ } ++ goto_buf[num = 0] = '\0'; ++do_goto: ++ 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 (special_handler != NULL) { ++ synth_printf("%s\n", msg_get(MSG_ERROR)); ++ return; ++ } ++ synth_printf("%s\n", msg_get(MSG_GOTO)); ++ special_handler = handle_goto; ++ return; ++} ++ ++static void speakup_help(struct vc_data *vc) ++{ ++ 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 = key_speakup = 16; ++ else ++ spk_key_locked = key_speakup = 0; ++} ++ ++typedef void(*spkup_hand)(struct vc_data *); ++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]) { ++ do_flush(); ++ (*spkup_handler[value])(vc); ++ } else { ++ if (inc_dec_var(value) < 0) ++ bleep(9); ++ } ++} ++ ++static const char *pad_chars = "0123456789+-*/\015,.?()"; ++ ++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 == NULL) ++ return 0; ++ ++ spk_lock(flags); ++ tty = vc->vc_tty; ++ if (type >= 0xf0) ++ type -= 0xf0; ++ if (type == KT_PAD && ++ (vc_kbd_led(kbd_table + fg_console, VC_NUMLOCK))) { ++ if (up_flag) { ++ spk_keydown = 0; ++ goto out; ++ } ++ value = spk_lastkey = pad_chars[value]; ++ spk_keydown++; ++ spk_parked &= 0xfe; ++ goto no_map; ++ } ++ if (keycode >= MAX_KEY) ++ goto no_map; ++ key_info = our_keys[keycode]; ++ if (key_info == 0) ++ 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 = 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; ++ do_flush(); ++ goto out; ++ } ++ if (up_flag) ++ goto out; ++ if (last_keycode == keycode && ++ last_spk_jiffy+MAX_DELAY > jiffies) { ++ spk_close_press = 1; ++ offset = 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 && special_handler == NULL) { ++ 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 (!no_intr) ++ do_flush(); ++ if (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 = (*special_handler)(vc, type, value, keycode); ++ spk_close_press = 0; ++ if (ret < 0) ++ bleep(9); ++ goto out; ++ } ++ last_keycode = 0; ++out: ++ spk_unlock(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 */ ++ ++ if (vc->vc_mode == KD_GRAPHICS) ++ return ret; ++ 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; ++ } ++ } ++ 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); ++ break; ++ case VT_DEALLOCATE: ++ speakup_deallocate(vc); ++ break; ++ case VT_WRITE: ++ if (param->c == '\b') ++ speakup_bs(vc); ++ else ++ if (param->c < 0x100) { ++ char 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; ++ ++ free_user_msgs(); ++ unregister_keyboard_notifier(&keyboard_notifier_block); ++ unregister_vt_notifier(&vt_notifier_block); ++ speakup_unregister_devsynth(); ++ del_timer(&cursor_timer); ++ ++ kthread_stop(speakup_task); ++ speakup_task = NULL; ++ mutex_lock(&spk_mutex); ++ synth_release(); ++ mutex_unlock(&spk_mutex); ++ ++ for (i = 0; i < MAXVARS; i++) ++ speakup_unregister_var(i); ++ ++ for (i = 0; i < 256; i++) { ++ if (characters[i] != default_chars[i]) ++ kfree(characters[i]); ++ } ++ for (i = 0; speakup_console[i]; i++) ++ kfree(speakup_console[i]); ++ speakup_kobj_exit(); ++} ++ ++/* call by: module_init() */ ++static int __init speakup_init(void) ++{ ++ int i; ++ struct st_spk_t *first_console; ++ struct vc_data *vc = vc_cons[fg_console].d; ++ struct var_t *var; ++ ++ initialize_msgs(); /* Initialize arrays for i18n. */ ++ first_console = kzalloc(sizeof(*first_console), GFP_KERNEL); ++ if (!first_console) ++ return -ENOMEM; ++ if (speakup_kobj_init() < 0) ++ return -ENOMEM; ++ ++ reset_default_chars(); ++ reset_default_chartab(); ++ ++ speakup_console[vc->vc_num] = first_console; ++ speakup_date(vc); ++ pr_info("speakup %s: initialized\n", SPEAKUP_VERSION); ++ ++ 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; punc_info[i].mask != 0; i++) ++ set_mask_bits(0, i, 2); ++ ++ set_key_info(key_defaults, key_buf); ++ if (quiet_boot) ++ spk_shut_up |= 0x01; ++ ++ for (i = 0; i < MAX_NR_CONSOLES; i++) ++ if (vc_cons[i].d) ++ speakup_allocate(vc_cons[i].d); ++ ++ pr_warn("synth name on entry is: %s\n", synth_name); ++ synth_init(synth_name); ++ speakup_register_devsynth(); ++ ++ register_keyboard_notifier(&keyboard_notifier_block); ++ register_vt_notifier(&vt_notifier_block); ++ ++ speakup_task = kthread_create(speakup_thread, NULL, "speakup"); ++ set_user_nice(speakup_task, 10); ++ if ( ! IS_ERR(speakup_task)) ++ wake_up_process(speakup_task); ++ else ++ return -ENOMEM; ++ return 0; ++} ++ ++module_init(speakup_init); ++module_exit(speakup_exit); ++ +--- a/drivers/staging/speakup/Makefile 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/Makefile 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,12 @@ ++KERNELDIR = /lib/modules/`uname -r`/build ++ ++all: modules ++ ++modules: ++ make -C $(KERNELDIR) M=`pwd` `cat allmodule.mk` ++ ++modules_install: ++ make INSTALL_MOD_DIR=speakup -C $(KERNELDIR) M=`pwd` `cat allmodule.mk` $@ ++ ++clean: ++ make -C $(KERNELDIR) M=`pwd` `cat allmodule.mk` $@ +--- a/drivers/staging/speakup/selection.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/selection.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,152 @@ ++#include ++#include ++#include ++#include ++ ++#include "speakup.h" ++ ++/* ------ cut and paste ----- */ ++/* Don't take this from : 011-015 on the screen aren't spaces */ ++#define ishardspace(c) ((c) == ' ') ++ ++unsigned short xs, ys, xe, ye; /* our region points */ ++ ++/* Variables for selection control. */ ++/* must not be disallocated */ ++struct vc_data *spk_sel_cons; ++/* cleared by clear_selection */ ++static int sel_start = -1; ++static int sel_end; ++static int sel_buffer_lth; ++static char *sel_buffer; ++ ++static unsigned char sel_pos(int n) ++{ ++ return inverse_translate(spk_sel_cons, screen_glyph(spk_sel_cons, n)); ++} ++ ++void speakup_clear_selection(void) ++{ ++ sel_start = -1; ++} ++ ++/* does screen address p correspond to character at LH/RH edge of screen? */ ++static int atedge(const int p, int size_row) ++{ ++ return (!(p % size_row) || !((p + 2) % size_row)); ++} ++ ++/* constrain v such that v <= u */ ++static unsigned short limit(const unsigned short v, const unsigned short u) ++{ ++ return (v > u) ? u : v; ++} ++ ++int speakup_set_selection(struct tty_struct *tty) ++{ ++ int new_sel_start, new_sel_end; ++ char *bp, *obp; ++ int i, ps, pe; ++ struct vc_data *vc = vc_cons[fg_console].d; ++ ++ xs = limit(xs, vc->vc_cols - 1); ++ ys = limit(ys, vc->vc_rows - 1); ++ xe = limit(xe, vc->vc_cols - 1); ++ ye = limit(ye, vc->vc_rows - 1); ++ ps = ys * vc->vc_size_row + (xs << 1); ++ pe = ye * vc->vc_size_row + (xe << 1); ++ ++ if (ps > pe) { ++ /* make sel_start <= sel_end */ ++ int tmp = ps; ++ ps = pe; ++ pe = tmp; ++ } ++ ++ if (spk_sel_cons != vc_cons[fg_console].d) { ++ speakup_clear_selection(); ++ spk_sel_cons = vc_cons[fg_console].d; ++ printk(KERN_WARNING ++ "Selection: mark console not the same as cut\n"); ++ return -EINVAL; ++ } ++ ++ new_sel_start = ps; ++ new_sel_end = pe; ++ ++ /* select to end of line if on trailing space */ ++ if (new_sel_end > new_sel_start && ++ !atedge(new_sel_end, vc->vc_size_row) && ++ ishardspace(sel_pos(new_sel_end))) { ++ for (pe = new_sel_end + 2; ; pe += 2) ++ if (!ishardspace(sel_pos(pe)) || ++ atedge(pe, vc->vc_size_row)) ++ break; ++ if (ishardspace(sel_pos(pe))) ++ new_sel_end = pe; ++ } ++ if ((new_sel_start == sel_start) && (new_sel_end == sel_end)) ++ return 0; /* no action required */ ++ ++ sel_start = new_sel_start; ++ sel_end = new_sel_end; ++ /* Allocate a new buffer before freeing the old one ... */ ++ bp = kmalloc((sel_end-sel_start)/2+1, GFP_ATOMIC); ++ if (!bp) { ++ printk(KERN_WARNING "selection: kmalloc() failed\n"); ++ speakup_clear_selection(); ++ return -ENOMEM; ++ } ++ kfree(sel_buffer); ++ sel_buffer = bp; ++ ++ obp = bp; ++ for (i = sel_start; i <= sel_end; i += 2) { ++ *bp = sel_pos(i); ++ if (!ishardspace(*bp++)) ++ obp = bp; ++ if (!((i + 2) % vc->vc_size_row)) { ++ /* strip trailing blanks from line and add newline, ++ unless non-space at end of line. */ ++ if (obp != bp) { ++ bp = obp; ++ *bp++ = '\r'; ++ } ++ obp = bp; ++ } ++ } ++ sel_buffer_lth = bp - sel_buffer; ++ return 0; ++} ++ ++int speakup_paste_selection(struct tty_struct *tty) ++{ ++ struct vc_data *vc = (struct vc_data *) tty->driver_data; ++ int pasted = 0, count; ++ DECLARE_WAITQUEUE(wait, current); ++ add_wait_queue(&vc->paste_wait, &wait); ++ while (sel_buffer && sel_buffer_lth > pasted) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ if (test_bit(TTY_THROTTLED, &tty->flags)) { ++ if (in_atomic()) ++ /* can't be performed in an interrupt handler, abort */ ++ break; ++ schedule(); ++ continue; ++ } ++ count = sel_buffer_lth - pasted; ++ count = min_t(int, count, tty->receive_room); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) ++ tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, 0, count); ++#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) ++ tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted, 0, count); ++#else ++ tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count); ++#endif ++ pasted += count; ++ } ++ remove_wait_queue(&vc->paste_wait, &wait); ++ current->state = TASK_RUNNING; ++ return 0; ++} ++ +--- a/drivers/staging/speakup/serialio.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/serialio.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,208 @@ ++#include ++#include ++ ++#include "spk_types.h" ++#include "speakup.h" ++#include "spk_priv.h" ++#include "serialio.h" ++ ++static void start_serial_interrupt(int irq); ++ ++static struct serial_state rs_table[] = { ++ SERIAL_PORT_DFNS ++}; ++static struct serial_state *serstate; ++static int timeouts; ++ ++struct serial_state *spk_serial_init(int index) ++{ ++ int baud = 9600, quot = 0; ++ unsigned int cval = 0; ++ int cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8; ++ struct serial_state *ser = NULL; ++ ++ ser = rs_table + index; ++ /* Divisor, bytesize and parity */ ++ quot = ser->baud_base / baud; ++ cval = cflag & (CSIZE | CSTOPB); ++#if defined(__powerpc__) || defined(__alpha__) ++ cval >>= 8; ++#else /* !__powerpc__ && !__alpha__ */ ++ cval >>= 4; ++#endif /* !__powerpc__ && !__alpha__ */ ++ if (cflag & PARENB) ++ cval |= UART_LCR_PARITY; ++ if (!(cflag & PARODD)) ++ cval |= UART_LCR_EPAR; ++ if (synth_request_region(ser->port, 8)) { ++ /* try to take it back. */ ++ printk("Ports not available, trying to steal them\n"); ++ __release_region(&ioport_resource, ser->port, 8); ++ if (synth_request_region(ser->port, 8)) ++ return NULL; ++ } ++ ++ /* Disable UART interrupts, set DTR and RTS high ++ * and set speed. */ ++ outb(cval | UART_LCR_DLAB, ser->port + UART_LCR); /* set DLAB */ ++ outb(quot & 0xff, ser->port + UART_DLL); /* LS of divisor */ ++ outb(quot >> 8, ser->port + UART_DLM); /* MS of divisor */ ++ outb(cval, ser->port + UART_LCR); /* reset DLAB */ ++ ++ /* Turn off Interrupts */ ++ outb(0, ser->port + UART_IER); ++ outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR); ++ ++ /* If we read 0xff from the LSR, there is no UART here. */ ++ if (inb(ser->port + UART_LSR) == 0xff) { ++ synth_release_region(ser->port, 8); ++ serstate = NULL; ++ return NULL; ++ } ++ ++ mdelay(1); ++ speakup_info.port_tts = ser->port; ++ serstate = ser; ++ ++ start_serial_interrupt(ser->irq); ++ ++ return ser; ++} ++ ++static irqreturn_t synth_readbuf_handler(int irq, void *dev_id) ++{ ++ unsigned long flags; ++/*printk(KERN_ERR "in irq\n"); */ ++/*pr_warn("in IRQ\n"); */ ++ int c; ++ spk_lock(flags); ++ while (inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR) { ++ ++ c = inb_p(speakup_info.port_tts+UART_RX); ++ synth->read_buff_add((u_char) c); ++/*printk(KERN_ERR "c = %d\n", c); */ ++/*pr_warn("C = %d\n", c); */ ++ } ++ spk_unlock(flags); ++ return IRQ_HANDLED; ++} ++ ++static void start_serial_interrupt(int irq) ++{ ++ int rv; ++ ++ if (synth->read_buff_add == NULL) ++ return; ++ ++ rv = request_irq(irq, synth_readbuf_handler, IRQF_SHARED, ++ "serial", (void *) synth_readbuf_handler); ++ ++ if (rv) ++ printk(KERN_ERR "Unable to request Speakup serial I R Q\n"); ++ /* Set MCR */ ++ outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, ++ speakup_info.port_tts + UART_MCR); ++ /* Turn on Interrupts */ ++ outb(UART_IER_MSI|UART_IER_RLSI|UART_IER_RDI, ++ speakup_info.port_tts + UART_IER); ++ inb(speakup_info.port_tts+UART_LSR); ++ inb(speakup_info.port_tts+UART_RX); ++ inb(speakup_info.port_tts+UART_IIR); ++ inb(speakup_info.port_tts+UART_MSR); ++ outb(1, speakup_info.port_tts + UART_FCR); /* Turn FIFO On */ ++} ++ ++void stop_serial_interrupt(void) ++{ ++ if (speakup_info.port_tts == 0) ++ return; ++ ++ if (synth->read_buff_add == NULL) ++ return; ++ ++ /* Turn off interrupts */ ++ outb(0, speakup_info.port_tts+UART_IER); ++ /* Free IRQ */ ++ free_irq(serstate->irq, (void *) synth_readbuf_handler); ++} ++ ++int wait_for_xmitr(void) ++{ ++ int tmout = SPK_XMITR_TIMEOUT; ++ if ((synth->alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) { ++ pr_warn("%s: too many timeouts, deactivating speakup\n", synth->long_name); ++ synth->alive = 0; ++ /* No synth any more, so nobody will restart TTYs, and we thus ++ * need to do it ourselves. Now that there is no synth we can ++ * let application flood anyway */ ++ speakup_start_ttys(); ++ timeouts = 0; ++ return 0; ++ } ++ while (spk_serial_tx_busy()) { ++ if (--tmout == 0) { ++ pr_warn("%s: timed out (tx busy)\n", synth->long_name); ++ timeouts++; ++ return 0; ++ } ++ udelay(1); ++ } ++ tmout = SPK_CTS_TIMEOUT; ++ while (!((inb_p(speakup_info.port_tts + UART_MSR)) & UART_MSR_CTS)) { ++ /* CTS */ ++ if (--tmout == 0) { ++ // pr_warn("%s: timed out (cts)\n", synth->long_name); ++ timeouts++; ++ return 0; ++ } ++ udelay(1); ++ } ++ timeouts = 0; ++ return 1; ++} ++ ++unsigned char spk_serial_in(void) ++{ ++ int tmout = SPK_SERIAL_TIMEOUT; ++ ++ while (!(inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)) { ++ if (--tmout == 0) { ++ pr_warn("time out while waiting for input.\n"); ++ return 0xff; ++ } ++ udelay(1); ++ } ++ return inb_p(speakup_info.port_tts + UART_RX); ++} ++EXPORT_SYMBOL_GPL(spk_serial_in); ++ ++unsigned char spk_serial_in_nowait(void) ++{ ++ unsigned char lsr; ++ ++ lsr = inb_p(speakup_info.port_tts + UART_LSR); ++ if (!(lsr & UART_LSR_DR)) ++ return 0; ++ return inb_p(speakup_info.port_tts + UART_RX); ++} ++EXPORT_SYMBOL_GPL(spk_serial_in_nowait); ++ ++int spk_serial_out(const char ch) ++{ ++ if (synth->alive && wait_for_xmitr()) { ++ outb_p(ch, speakup_info.port_tts); ++ return 1; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(spk_serial_out); ++ ++void spk_serial_release(void) ++{ ++ if (speakup_info.port_tts == 0) ++ return; ++ synth_release_region(speakup_info.port_tts, 8); ++ speakup_info.port_tts = 0; ++} ++EXPORT_SYMBOL_GPL(spk_serial_release); ++ +--- a/drivers/staging/speakup/serialio.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/serialio.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,55 @@ ++#ifndef _SPEAKUP_SERIAL_H ++#define _SPEAKUP_SERIAL_H ++ ++#include /* for rs_table, serial constants & ++ serial_uart_config */ ++#include /* for more serial constants */ ++#include /* for struct serial_state */ ++#ifndef __sparc__ ++#include ++#endif ++ ++/* countdown values for serial timeouts in us */ ++#define SPK_SERIAL_TIMEOUT 100000 ++/* countdown values transmitter/dsr timeouts in us */ ++#define SPK_XMITR_TIMEOUT 100000 ++/* countdown values cts timeouts in us */ ++#define SPK_CTS_TIMEOUT 100000 ++/* check ttyS0 ... ttyS3 */ ++#define SPK_LO_TTY 0 ++#define SPK_HI_TTY 3 ++/* # of timeouts permitted before disable */ ++#define NUM_DISABLE_TIMEOUTS 3 ++/* buffer timeout in ms */ ++#define SPK_TIMEOUT 100 ++#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) ++ ++#define spk_serial_tx_busy() ((inb(speakup_info.port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY) ++ ++/* 2.6.22 doesn't have them any more, hardcode it for now (these values should ++ * be fine for 99% cases) */ ++#ifndef BASE_BAUD ++#define BASE_BAUD (1843200 / 16) ++#endif ++#ifndef STD_COM_FLAGS ++#ifdef CONFIG_SERIAL_DETECT_IRQ ++#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) ++#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) ++#else ++#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) ++#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF ++#endif ++#endif ++#ifndef SERIAL_PORT_DFNS ++#define SERIAL_PORT_DFNS \ ++ /* UART CLK PORT IRQ FLAGS */ \ ++ { 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \ ++ { 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \ ++ { 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \ ++ { 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ ++#endif ++#ifndef IRQF_SHARED ++#define IRQF_SHARED SA_SHIRQ ++#endif ++ ++#endif +--- a/drivers/staging/speakup/speakup_acnt.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_acnt.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,16 @@ ++/* speakup_acntpc.h - header file for speakups Accent-PC driver. */ ++ ++#define SYNTH_IO_EXTENT 0x02 ++ ++#define SYNTH_CLEAR 0x18 /* stops speech */ ++ ++ /* Port Status Flags */ ++#define SYNTH_READABLE 0x01 /* mask for bit which is nonzero if a ++ byte can be read from the data port */ ++#define SYNTH_WRITABLE 0x02 /* mask for RDY bit, which when set to ++ 1, indicates the data port is ready ++ to accept a byte of data. */ ++#define SYNTH_QUIET 'S' /* synth is not speaking */ ++#define SYNTH_FULL 'F' /* synth is full. */ ++#define SYNTH_ALMOST_EMPTY 'M' /* synth has les than 2 seconds of text left */ ++#define SYNTH_SPEAKING 's' /* synth is speaking and has a fare way to go */ +--- a/drivers/staging/speakup/speakup_acntpc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_acntpc.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,323 @@ ++/* ++ * written by: Kirk Reiser ++ * this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * this code is specificly written as a driver for the speakup screenreview ++ * package and is not a general device driver. ++ * This driver is for the Aicom Acent PC internal synthesizer. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "serialio.h" ++#include "speakup.h" ++#include "speakup_acnt.h" /* local header file for Accent values */ ++ ++#define DRV_VERSION "2.9" ++#define synth_readable() (inb_p(synth_port_control) & SYNTH_READABLE) ++#define synth_writable() (inb_p(synth_port_control) & SYNTH_WRITABLE) ++#define synth_full() (inb_p(speakup_info.port_tts + UART_RX) == 'F') ++#define PROCSPEECH '\r' ++ ++static int synth_probe(struct spk_synth *synth); ++static void accent_release(void); ++static const char *synth_immediate(struct spk_synth *synth, const char *buf); ++static void do_catch_up(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++ ++static int synth_port_control; ++static int port_forced; ++static unsigned int synth_portlist[] = { 0x2a8, 0 }; ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\033P8" }}, ++ { CAPS_STOP, .u.s = {"\033P5" }}, ++ { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" }}, ++ { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL }}, ++ { VOL, .u.n = {"\033A%d", 5, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/acntpc. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_acntpc = { ++ .name = "acntpc", ++ .version = DRV_VERSION, ++ .long_name = "Accent PC", ++ .init = "\033=X \033Oi\033T2\033=M\033N1\n", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 1000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = accent_release, ++ .synth_immediate = synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_nop, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "acntpc", ++ }, ++}; ++ ++static const char *synth_immediate(struct spk_synth *synth, const char *buf) ++{ ++ u_char ch; ++ while ((ch = *buf)) { ++ int timeout = SPK_XMITR_TIMEOUT; ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ if (synth_full()) ++ return buf; ++ while (synth_writable()) { ++ if (!--timeout) ++ return buf; ++ udelay(1); ++ } ++ outb_p(ch, speakup_info.port_tts); ++ buf++; ++ } ++ return 0; ++} ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ unsigned long flags; ++ unsigned long jiff_max; ++ int timeout; ++ int delay_time_val; ++ int jiffy_delta_val; ++ int full_time_val; ++ struct var_t *delay_time; ++ struct var_t *full_time; ++ struct var_t *jiffy_delta; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ full_time = get_var(FULL); ++ ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ ++ jiff_max = jiffies + jiffy_delta_val; ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ set_current_state(TASK_INTERRUPTIBLE); ++ full_time_val = full_time->u.n.value; ++ spk_unlock(flags); ++ if (synth_full()) { ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ timeout = SPK_XMITR_TIMEOUT; ++ while (synth_writable()) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ spk_lock(flags); ++ ch = synth_buffer_getc(); ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ outb_p(ch, speakup_info.port_tts); ++ if (jiffies >= jiff_max && ch == SPACE) { ++ timeout = SPK_XMITR_TIMEOUT; ++ while (synth_writable()) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ outb_p(PROCSPEECH, speakup_info.port_tts); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ jiff_max = jiffies+jiffy_delta_val; ++ } ++ } ++ timeout = SPK_XMITR_TIMEOUT; ++ while (synth_writable()) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ outb_p(PROCSPEECH, speakup_info.port_tts); ++} ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ outb_p(SYNTH_CLEAR, speakup_info.port_tts); ++} ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ unsigned int port_val = 0; ++ int i = 0; ++ pr_info("Probing for %s.\n", synth->long_name); ++ if (port_forced) { ++ speakup_info.port_tts = port_forced; ++ pr_info("probe forced to %x by kernel command line\n", ++ speakup_info.port_tts); ++ if (synth_request_region(speakup_info.port_tts-1, ++ SYNTH_IO_EXTENT)) { ++ pr_warn("sorry, port already reserved\n"); ++ return -EBUSY; ++ } ++ port_val = inw(speakup_info.port_tts-1); ++ synth_port_control = speakup_info.port_tts-1; ++ } else { ++ for (i = 0; synth_portlist[i]; i++) { ++ if (synth_request_region(synth_portlist[i], ++ SYNTH_IO_EXTENT)) { ++ pr_warn("request_region: failed with 0x%x, %d\n", ++ synth_portlist[i], SYNTH_IO_EXTENT); ++ continue; ++ } ++ port_val = inw(synth_portlist[i]) & 0xfffc; ++ if (port_val == 0x53fc) { ++ /* 'S' and out&input bits */ ++ synth_port_control = synth_portlist[i]; ++ speakup_info.port_tts = synth_port_control+1; ++ break; ++ } ++ } ++ } ++ port_val &= 0xfffc; ++ if (port_val != 0x53fc) { ++ /* 'S' and out&input bits */ ++ pr_info("%s: not found\n", synth->long_name); ++ synth_release_region(synth_portlist[i], SYNTH_IO_EXTENT); ++ synth_port_control = 0; ++ return -ENODEV; ++ } ++ pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name, ++ synth_port_control, synth_port_control+SYNTH_IO_EXTENT-1, ++ synth->version); ++ synth->alive = 1; ++ return 0; ++} ++ ++static void accent_release(void) ++{ ++ if (speakup_info.port_tts) ++ synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT); ++ speakup_info.port_tts = 0; ++} ++ ++module_param_named(port, port_forced, int, S_IRUGO); ++module_param_named(start, synth_acntpc.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init acntpc_init(void) ++{ ++ return synth_add(&synth_acntpc); ++} ++ ++static void __exit acntpc_exit(void) ++{ ++ synth_remove(&synth_acntpc); ++} ++ ++module_init(acntpc_init); ++module_exit(acntpc_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Accent PC synthesizer"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_acntsa.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_acntsa.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,160 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * this code is specificly written as a driver for the speakup screenreview ++ * package and is not a general device driver. ++ */ ++ ++#include "spk_priv.h" ++#include "speakup.h" ++#include "speakup_acnt.h" /* local header file for Accent values */ ++ ++#define DRV_VERSION "2.10" ++#define synth_full() (inb_p(speakup_info.port_tts + UART_RX) == 'F') ++#define PROCSPEECH '\r' ++ ++static int synth_probe(struct spk_synth *synth); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\033P8" }}, ++ { CAPS_STOP, .u.s = {"\033P5" }}, ++ { RATE, .u.n = {"\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" }}, ++ { PITCH, .u.n = {"\033P%d", 5, 0, 9, 0, 0, NULL }}, ++ { VOL, .u.n = {"\033A%d", 9, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\033V%d", 5, 0, 9, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/acntsa. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_acntsa = { ++ .name = "acntsa", ++ .version = DRV_VERSION, ++ .long_name = "Accent-SA", ++ .init = "\033T2\033=M\033Oi\033N1\n", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 400, ++ .trigger = 50, ++ .jiffies = 30, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "acntsa", ++ }, ++}; ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ int failed; ++ ++ failed = serial_synth_probe(synth); ++ if (failed == 0) { ++ spk_synth_immediate(synth, "\033=R\r"); ++ mdelay(100); ++ } ++ synth->alive = !failed; ++ return failed; ++} ++ ++module_param_named(ser, synth_acntsa.ser, int, S_IRUGO); ++module_param_named(start, synth_acntsa.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init acntsa_init(void) ++{ ++ return synth_add(&synth_acntsa); ++} ++ ++static void __exit acntsa_exit(void) ++{ ++ synth_remove(&synth_acntsa); ++} ++ ++module_init(acntsa_init); ++module_exit(acntsa_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Accent SA synthesizer"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_apollo.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_apollo.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,221 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * this code is specificly written as a driver for the speakup screenreview ++ * package and is not a general device driver. ++ */ ++#include ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "serialio.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.20" ++#define SYNTH_CLEAR 0x18 ++#define PROCSPEECH '\r' ++ ++static void do_catch_up(struct spk_synth *synth); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"cap, " }}, ++ { CAPS_STOP, .u.s = {"" }}, ++ { RATE, .u.n = {"@W%d", 6, 1, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"@F%x", 10, 0, 15, 0, 0, NULL }}, ++ { VOL, .u.n = {"@A%x", 10, 0, 15, 0, 0, NULL }}, ++ { VOICE, .u.n = {"@V%d", 1, 1, 6, 0, 0, NULL }}, ++ { LANG, .u.n = {"@=%d,", 1, 1, 4, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/apollo. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute lang_attribute = ++ __ATTR(lang, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &lang_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_apollo = { ++ .name = "apollo", ++ .version = DRV_VERSION, ++ .long_name = "Apollo", ++ .init = "@R3@D0@K1\r", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "apollo", ++ }, ++}; ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ unsigned long flags; ++ unsigned long jiff_max; ++ struct var_t *jiffy_delta; ++ struct var_t *delay_time; ++ struct var_t *full_time; ++ int full_time_val = 0; ++ int delay_time_val = 0; ++ int jiffy_delta_val = 0; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ full_time = get_var(FULL); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ jiff_max = jiffies + jiffy_delta_val; ++ ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ full_time_val = full_time->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ ch = synth_buffer_peek(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ full_time_val = full_time->u.n.value; ++ spk_unlock(flags); ++ if (!spk_serial_out(ch)) { ++ outb(UART_MCR_DTR, speakup_info.port_tts + UART_MCR); ++ outb(UART_MCR_DTR | UART_MCR_RTS, ++ speakup_info.port_tts + UART_MCR); ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ continue; ++ } ++ if ((jiffies >= jiff_max) && (ch == SPACE)) { ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ full_time_val = full_time->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ if (spk_serial_out(synth->procspeech)) ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ else ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ jiff_max = jiffies + jiffy_delta_val; ++ } ++ set_current_state(TASK_RUNNING); ++ spk_lock(flags); ++ synth_buffer_getc(); ++ spk_unlock(flags); ++ } ++ spk_serial_out(PROCSPEECH); ++} ++ ++module_param_named(ser, synth_apollo.ser, int, S_IRUGO); ++module_param_named(start, synth_apollo.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init apollo_init(void) ++{ ++ return synth_add(&synth_apollo); ++} ++ ++static void __exit apollo_exit(void) ++{ ++ synth_remove(&synth_apollo); ++} ++ ++module_init(apollo_init); ++module_exit(apollo_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Apollo II synthesizer"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_audptr.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_audptr.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,191 @@ ++/* ++ * originally written by: Kirk Reiser ++ * this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include "spk_priv.h" ++#include "speakup.h" ++#include "serialio.h" ++ ++#define DRV_VERSION "2.10" ++#define SYNTH_CLEAR 0x18 /* flush synth buffer */ ++#define PROCSPEECH '\r' /* start synth processing speech char */ ++ ++static int synth_probe(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x05[f99]" }}, ++ { CAPS_STOP, .u.s = {"\x05[f80]" }}, ++ { RATE, .u.n = {"\x05[r%d]", 10, 0, 20, 100, -10, NULL }}, ++ { PITCH, .u.n = {"\x05[f%d]", 80, 39, 4500, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x05[g%d]", 21, 0, 40, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x05[s%d]", 9, 0, 63, 0, 0, 0 }}, ++ { PUNCT, .u.n = {"\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/audptr. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_audptr = { ++ .name = "audptr", ++ .version = DRV_VERSION, ++ .long_name = "Audapter", ++ .init = "\x05[D1]\x05[Ol]", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 400, ++ .trigger = 50, ++ .jiffies = 30, ++ .full = 18000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "audptr", ++ }, ++}; ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ int timeout = SPK_XMITR_TIMEOUT; ++ while (spk_serial_tx_busy()) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ outb(SYNTH_CLEAR, speakup_info.port_tts); ++ spk_serial_out(PROCSPEECH); ++} ++ ++static void synth_version(struct spk_synth *synth) ++{ ++ unsigned char test = 0; ++ char synth_id[40] = ""; ++ spk_synth_immediate(synth, "\x05[Q]"); ++ synth_id[test] = spk_serial_in(); ++ if (synth_id[test] == 'A') { ++ do { ++ /* read version string from synth */ ++ synth_id[++test] = spk_serial_in(); ++ } while (synth_id[test] != '\n' && test < 32); ++ synth_id[++test] = 0x00; ++ } ++ if (synth_id[0] == 'A') ++ pr_info("%s version: %s", synth->long_name, synth_id); ++} ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ int failed = 0; ++ ++ failed = serial_synth_probe(synth); ++ if (failed == 0) ++ synth_version(synth); ++ synth->alive = !failed; ++ return 0; ++} ++ ++module_param_named(ser, synth_audptr.ser, int, S_IRUGO); ++module_param_named(start, synth_audptr.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init audptr_init(void) ++{ ++ return synth_add(&synth_audptr); ++} ++ ++static void __exit audptr_exit(void) ++{ ++ synth_remove(&synth_audptr); ++} ++ ++module_init(audptr_init); ++module_exit(audptr_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Audapter synthesizer"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_bns.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_bns.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,143 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * this code is specificly written as a driver for the speakup screenreview ++ * package and is not a general device driver. ++ */ ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.10" ++#define SYNTH_CLEAR 0x18 ++#define PROCSPEECH '\r' ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x05\x31\x32P" }}, ++ { CAPS_STOP, .u.s = {"\x05\x38P" }}, ++ { RATE, .u.n = {"\x05%dE", 8, 1, 16, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x05%dP", 8, 0, 16, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x05%dV", 8, 0, 16, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x05%dT", 8, 0, 16, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/bns. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_bns = { ++ .name = "bns", ++ .version = DRV_VERSION, ++ .long_name = "Braille 'N Speak", ++ .init = "\x05Z\x05\x43", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "bns", ++ }, ++}; ++ ++module_param_named(ser, synth_bns.ser, int, S_IRUGO); ++module_param_named(start, synth_bns.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init bns_init(void) ++{ ++ return synth_add(&synth_bns); ++} ++ ++static void __exit bns_exit(void) ++{ ++ synth_remove(&synth_bns); ++} ++ ++module_init(bns_init); ++module_exit(bns_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Braille 'n Speak synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_decext.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_decext.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,238 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "serialio.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.13" ++#define SYNTH_CLEAR 0x03 ++#define PROCSPEECH 0x0b ++static unsigned char last_char; ++#define get_last_char() ((inb_p(speakup_info.port_tts + UART_LSR) & UART_LSR_DR)? \ ++ (last_char = inb_p(speakup_info.port_tts + UART_RX)) : last_char) ++#define synth_full() (get_last_char() == 0x13) ++ ++static void do_catch_up(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++ ++static int in_escape; ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"[:dv ap 222]" }}, ++ { CAPS_STOP, .u.s = {"[:dv ap 100]" }}, ++ { RATE, .u.n = {"[:ra %d]", 7, 0, 9, 150, 25, NULL }}, ++ { PITCH, .u.n = {"[:dv ap %d]", 100, 0, 100, 0, 0, NULL }}, ++ { VOL, .u.n = {"[:dv gv %d]", 13, 0, 16, 0, 5, NULL }}, ++ { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" }}, ++ { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/decext. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_decext = { ++ .name = "decext", ++ .version = DRV_VERSION, ++ .long_name = "Dectalk External", ++ .init = "[:pe -380]", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .flags = SF_DEC, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "decext", ++ }, ++}; ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ static u_char last = '\0'; ++ unsigned long flags; ++ unsigned long jiff_max; ++ struct var_t *jiffy_delta; ++ struct var_t *delay_time; ++ int jiffy_delta_val = 0; ++ int delay_time_val = 0; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ jiff_max = jiffies + jiffy_delta_val; ++ ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ ch = synth_buffer_peek(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = 0x0D; ++ if (synth_full() || !spk_serial_out(ch)) { ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ spk_lock(flags); ++ synth_buffer_getc(); ++ spk_unlock(flags); ++ if (ch == '[') ++ in_escape = 1; ++ else if (ch == ']') ++ in_escape = 0; ++ else if (ch <= SPACE) { ++ if (!in_escape && strchr(",.!?;:", last)) ++ spk_serial_out(PROCSPEECH); ++ if (jiffies >= jiff_max) { ++ if ( ! in_escape ) ++ spk_serial_out(PROCSPEECH); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ jiff_max = jiffies + jiffy_delta_val; ++ } ++ } ++ last = ch; ++ } ++ if (!in_escape) ++ spk_serial_out(PROCSPEECH); ++} ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ in_escape = 0; ++ spk_synth_immediate(synth, "\033P;10z\033\\"); ++} ++ ++module_param_named(ser, synth_decext.ser, int, S_IRUGO); ++module_param_named(start, synth_decext.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init decext_init(void) ++{ ++ return synth_add(&synth_decext); ++} ++ ++static void __exit decext_exit(void) ++{ ++ synth_remove(&synth_decext); ++} ++ ++module_init(decext_init); ++module_exit(decext_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for DECtalk External synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_dectlk.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_dectlk.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,306 @@ ++/* ++ * originally written by: Kirk Reiser ++ * this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "speakup.h" ++#include "spk_priv.h" ++#include "serialio.h" ++ ++#define DRV_VERSION "2.15" ++#define SYNTH_CLEAR 0x03 ++#define PROCSPEECH 0x0b ++static volatile int xoff; ++#define synth_full() (xoff) ++ ++static void do_catch_up(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++static void read_buff_add(u_char c); ++static unsigned char get_index(void); ++ ++static int in_escape; ++static int is_flushing; ++ ++static spinlock_t flush_lock; ++static DECLARE_WAIT_QUEUE_HEAD(flush); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"[:dv ap 200]" }}, ++ { CAPS_STOP, .u.s = {"[:dv ap 100]" }}, ++ { RATE, .u.n = {"[:ra %d]", 9, 0, 18, 150, 25, NULL }}, ++ { PITCH, .u.n = {"[:dv ap %d]", 80, 0, 200, 20, 0, NULL }}, ++ { VOL, .u.n = {"[:dv gv %d]", 13, 0, 14, 0, 5, NULL }}, ++ { PUNCT, .u.n = {"[:pu %c]", 0, 0, 2, 0, 0, "nsa" }}, ++ { VOICE, .u.n = {"[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/dectlk. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_dectlk = { ++ .name = "dectlk", ++ .version = DRV_VERSION, ++ .long_name = "Dectalk Express", ++ .init = "[:dv ap 100][:error sp]", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = read_buff_add, ++ .get_index = get_index, ++ .indexing = { ++ .command = "[:in re %d] ", ++ .lowindex = 1, ++ .highindex = 8, ++ .currindex = 1, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "dectlk", ++ }, ++}; ++ ++static int is_indnum(u_char *ch) ++{ ++ if ((*ch >= '0') && (*ch <= '9')) { ++ *ch = *ch - '0'; ++ return 1; ++ } ++ return 0; ++} ++ ++static u_char lastind = 0; ++ ++static unsigned char get_index(void) ++{ ++ u_char rv; ++ rv = lastind; ++ lastind = 0; ++ return rv; ++} ++ ++static void read_buff_add(u_char c) ++{ ++ static int ind = -1; ++ ++ if (c == 0x01) { ++ unsigned long flags; ++ spin_lock_irqsave(&flush_lock, flags); ++ is_flushing = 0; ++ wake_up_interruptible(&flush); ++ spin_unlock_irqrestore(&flush_lock, flags); ++ } else if (c == 0x13) { ++ xoff = 1; ++ } else if (c == 0x11) { ++ xoff = 0; ++ } else if (is_indnum(&c)) { ++ if (ind == -1) ++ ind = c; ++ else ++ ind = ind * 10 + c; ++ } else if ((c > 31) && (c < 127)) { ++ if (ind != -1) ++ lastind = (u_char)ind; ++ ind = -1; ++ } ++} ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ static u_char ch = 0; ++ static u_char last = '\0'; ++ unsigned long flags; ++ unsigned long jiff_max; ++ unsigned long timeout = msecs_to_jiffies(4000); ++ DEFINE_WAIT(wait); ++ struct var_t *jiffy_delta; ++ struct var_t *delay_time; ++ int jiffy_delta_val; ++ int delay_time_val; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ jiff_max = jiffies + jiffy_delta_val; ++ ++ while (!kthread_should_stop()) { ++ /* if no ctl-a in 4, send data anyway */ ++ spin_lock_irqsave(&flush_lock, flags); ++ while (is_flushing && timeout) { ++ prepare_to_wait(&flush, &wait, TASK_INTERRUPTIBLE); ++ spin_unlock_irqrestore(&flush_lock, flags); ++ timeout = schedule_timeout(timeout); ++ spin_lock_irqsave(&flush_lock, flags); ++ } ++ finish_wait(&flush, &wait); ++ is_flushing = 0; ++ spin_unlock_irqrestore(&flush_lock, flags); ++ ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ ch = synth_buffer_peek(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = 0x0D; ++ if (synth_full() || !spk_serial_out(ch)) { ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ spk_lock(flags); ++ synth_buffer_getc(); ++ spk_unlock(flags); ++ if (ch == '[') ++ in_escape = 1; ++ else if (ch == ']') ++ in_escape = 0; ++ else if (ch <= SPACE) { ++ if (!in_escape && strchr(",.!?;:", last)) ++ spk_serial_out(PROCSPEECH); ++ if (jiffies >= jiff_max) { ++ if ( ! in_escape ) ++ spk_serial_out(PROCSPEECH); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ jiff_max = jiffies + jiffy_delta_val; ++ } ++ } ++ last = ch; ++ } ++ if (!in_escape) ++ spk_serial_out(PROCSPEECH); ++} ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ if (in_escape) { ++ /* if in command output ']' so we don't get an error */ ++ spk_serial_out(']'); ++ } ++ in_escape = 0; ++ is_flushing = 1; ++ spk_serial_out(SYNTH_CLEAR); ++} ++ ++module_param_named(ser, synth_dectlk.ser, int, S_IRUGO); ++module_param_named(start, synth_dectlk.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init dectlk_init(void) ++{ ++ return synth_add(&synth_dectlk); ++} ++ ++static void __exit dectlk_exit(void) ++{ ++ synth_remove(&synth_dectlk); ++} ++ ++module_init(dectlk_init); ++module_exit(dectlk_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for DECtalk Express synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_dtlk.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_dtlk.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,379 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * package it's not a general device driver. ++ * This driver is for the RC Systems DoubleTalk PC internal synthesizer. ++ */ ++#include ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "serialio.h" ++#include "speakup_dtlk.h" /* local header file for DoubleTalk values */ ++#include "speakup.h" ++ ++#define DRV_VERSION "2.9" ++#define PROCSPEECH 0x00 ++#define synth_readable() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_READABLE) ++#define synth_writable() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_WRITABLE) ++#define synth_full() ((synth_status = inb_p(speakup_info.port_tts + UART_RX)) & TTS_ALMOST_FULL) ++ ++static int synth_probe(struct spk_synth *synth); ++static void dtlk_release(void); ++static const char *synth_immediate(struct spk_synth *synth, const char *buf); ++static void do_catch_up(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++ ++static int synth_lpc; ++static int port_forced; ++static unsigned int synth_portlist[] = ++ { 0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0 }; ++static u_char synth_status; ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x01+35p" }}, ++ { CAPS_STOP, .u.s = {"\x01-35p" }}, ++ { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }}, ++ { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL }}, ++ { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }}, ++ { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/dtlk. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute freq_attribute = ++ __ATTR(freq, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &freq_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_dtlk = { ++ .name = "dtlk", ++ .version = DRV_VERSION, ++ .long_name = "DoubleTalk PC", ++ .init = "\x01@\x01\x31y", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 30, ++ .jiffies = 50, ++ .full = 1000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = dtlk_release, ++ .synth_immediate = synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_nop, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = spk_serial_in_nowait, ++ .indexing = { ++ .command = "\x01%di", ++ .lowindex = 1, ++ .highindex = 5, ++ .currindex = 1, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "dtlk", ++ }, ++}; ++ ++static void spk_out(const char ch) ++{ ++ int timeout = SPK_XMITR_TIMEOUT; ++ while (synth_writable() == 0) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ outb_p(ch, speakup_info.port_tts); ++ timeout = SPK_XMITR_TIMEOUT; ++ while (synth_writable() != 0) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++} ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ unsigned long flags; ++ unsigned long jiff_max; ++ struct var_t *jiffy_delta; ++ struct var_t *delay_time; ++ int jiffy_delta_val; ++ int delay_time_val; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ jiff_max = jiffies + jiffy_delta_val; ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ set_current_state(TASK_INTERRUPTIBLE); ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ if (synth_full()) { ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ spk_lock(flags); ++ ch = synth_buffer_getc(); ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ spk_out(ch); ++ if ((jiffies >= jiff_max) && (ch == SPACE)) { ++ spk_out(PROCSPEECH); ++ spk_lock(flags); ++ delay_time_val = delay_time->u.n.value; ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ jiff_max = jiffies + jiffy_delta_val; ++ } ++ } ++ spk_out(PROCSPEECH); ++} ++ ++static const char *synth_immediate(struct spk_synth *synth, const char *buf) ++{ ++ u_char ch; ++ while ((ch = (u_char)*buf)) { ++ if (synth_full()) ++ return buf; ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ spk_out(ch); ++ buf++; ++ } ++ return 0; ++} ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ outb_p(SYNTH_CLEAR, speakup_info.port_tts); ++ while (synth_writable() != 0) ++ cpu_relax(); ++} ++ ++static char synth_read_tts(void) ++{ ++ u_char ch; ++ while (synth_readable() == 0) ++ cpu_relax(); ++ ch = synth_status & 0x7f; ++ outb_p(ch, speakup_info.port_tts); ++ while (synth_readable() != 0) ++ cpu_relax(); ++ return (char) ch; ++} ++ ++/* interrogate the DoubleTalk PC and return its settings */ ++static struct synth_settings *synth_interrogate(struct spk_synth *synth) ++{ ++ u_char *t; ++ static char buf[sizeof(struct synth_settings) + 1]; ++ int total, i; ++ static struct synth_settings status; ++ synth_immediate(synth, "\x18\x01?"); ++ for (total = 0, i = 0; i < 50; i++) { ++ buf[total] = synth_read_tts(); ++ if (total > 2 && buf[total] == 0x7f) ++ break; ++ if (total < sizeof(struct synth_settings)) ++ total++; ++ } ++ t = buf; ++ /* serial number is little endian */ ++ status.serial_number = t[0] + t[1]*256; ++ t += 2; ++ for (i = 0; *t != '\r'; t++) { ++ status.rom_version[i] = *t; ++ if (i < sizeof(status.rom_version)-1) ++ i++; ++ } ++ status.rom_version[i] = 0; ++ t++; ++ status.mode = *t++; ++ status.punc_level = *t++; ++ status.formant_freq = *t++; ++ status.pitch = *t++; ++ status.speed = *t++; ++ status.volume = *t++; ++ status.tone = *t++; ++ status.expression = *t++; ++ status.ext_dict_loaded = *t++; ++ status.ext_dict_status = *t++; ++ status.free_ram = *t++; ++ status.articulation = *t++; ++ status.reverb = *t++; ++ status.eob = *t++; ++ return &status; ++} ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ unsigned int port_val = 0; ++ int i = 0; ++ struct synth_settings *sp; ++ pr_info("Probing for DoubleTalk.\n"); ++ if (port_forced) { ++ speakup_info.port_tts = port_forced; ++ pr_info("probe forced to %x by kernel command line\n", ++ speakup_info.port_tts); ++ if (synth_request_region(speakup_info.port_tts-1, ++ SYNTH_IO_EXTENT)) { ++ pr_warn("sorry, port already reserved\n"); ++ return -EBUSY; ++ } ++ port_val = inw(speakup_info.port_tts-1); ++ synth_lpc = speakup_info.port_tts-1; ++ } else { ++ for (i = 0; synth_portlist[i]; i++) { ++ if (synth_request_region(synth_portlist[i], ++ SYNTH_IO_EXTENT)) ++ continue; ++ port_val = inw(synth_portlist[i]) & 0xfbff; ++ if (port_val == 0x107f) { ++ synth_lpc = synth_portlist[i]; ++ speakup_info.port_tts = synth_lpc+1; ++ break; ++ } ++ synth_release_region(synth_portlist[i], ++ SYNTH_IO_EXTENT); ++ } ++ } ++ port_val &= 0xfbff; ++ if (port_val != 0x107f) { ++ pr_info("DoubleTalk PC: not found\n"); ++ return -ENODEV; ++ } ++ while (inw_p(synth_lpc) != 0x147f) ++ cpu_relax(); /* wait until it's ready */ ++ sp = synth_interrogate(synth); ++ pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n", ++ synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1, ++ sp->rom_version, sp->serial_number, synth->version); ++ synth->alive = 1; ++ return 0; ++} ++ ++static void dtlk_release(void) ++{ ++ if (speakup_info.port_tts) ++ synth_release_region(speakup_info.port_tts-1, SYNTH_IO_EXTENT); ++ speakup_info.port_tts = 0; ++} ++ ++module_param_named(port, port_forced, int, S_IRUGO); ++module_param_named(start, synth_dtlk.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init dtlk_init(void) ++{ ++ return synth_add(&synth_dtlk); ++} ++ ++static void __exit dtlk_exit(void) ++{ ++ synth_remove(&synth_dtlk); ++} ++ ++module_init(dtlk_init); ++module_exit(dtlk_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for DoubleTalk PC synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_dtlk.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_dtlk.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,54 @@ ++/* speakup_dtlk.h - header file for speakups DoubleTalk driver. */ ++ ++#define SYNTH_IO_EXTENT 0x02 ++#define SYNTH_CLEAR 0x18 /* stops speech */ ++ /* TTS Port Status Flags */ ++#define TTS_READABLE 0x80 /* mask for bit which is nonzero if a ++ byte can be read from the TTS port */ ++#define TTS_SPEAKING 0x40 /* mask for SYNC bit, which is nonzero ++ while DoubleTalk is producing ++ output with TTS, PCM or CVSD ++ synthesizers or tone generators ++ (that is, all but LPC) */ ++#define TTS_SPEAKING2 0x20 /* mask for SYNC2 bit, ++ which falls to zero up to 0.4 sec ++ before speech stops */ ++#define TTS_WRITABLE 0x10 /* mask for RDY bit, which when set to ++ 1, indicates the TTS port is ready ++ to accept a byte of data. The RDY ++ bit goes zero 2-3 usec after ++ writing, and goes 1 again 180-190 ++ usec later. */ ++#define TTS_ALMOST_FULL 0x08 /* mask for AF bit: When set to 1, ++ indicates that less than 300 bytes ++ are available in the TTS input ++ buffer. AF is always 0 in the PCM, ++ TGN and CVSD modes. */ ++#define TTS_ALMOST_EMPTY 0x04 /* mask for AE bit: When set to 1, ++ indicates that less than 300 bytes ++ are remaining in DoubleTalk's input ++ (TTS or PCM) buffer. AE is always 1 ++ in the TGN and CVSD modes. */ ++ ++ /* data returned by Interrogate command */ ++struct synth_settings { ++ u_short serial_number; /* 0-7Fh:0-7Fh */ ++ u_char rom_version[24]; /* null terminated string */ ++ u_char mode; /* 0=Character; 1=Phoneme; 2=Text */ ++ u_char punc_level; /* nB; 0-7 */ ++ u_char formant_freq; /* nF; 0-9 */ ++ u_char pitch; /* nP; 0-99 */ ++ u_char speed; /* nS; 0-9 */ ++ u_char volume; /* nV; 0-9 */ ++ u_char tone; /* nX; 0-2 */ ++ u_char expression; /* nE; 0-9 */ ++ u_char ext_dict_loaded; /* 1=exception dictionary loaded */ ++ u_char ext_dict_status; /* 1=exception dictionary enabled */ ++ u_char free_ram; /* # pages (truncated) remaining for ++ * text buffer */ ++ u_char articulation; /* nA; 0-9 */ ++ u_char reverb; /* nR; 0-9 */ ++ u_char eob; /* 7Fh value indicating end of ++ * parameter block */ ++ u_char has_indexing; /* nonzero if indexing is implemented */ ++}; +--- a/drivers/staging/speakup/speakup_dummy.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_dummy.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,144 @@ ++/* ++ * originally written by: Kirk Reiser ++ * this version considerably modified by David Borowski, david575@rogers.com ++ * eventually modified by Samuel Thibault ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * Copyright (C) 2007 Samuel Thibault. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define PROCSPEECH '\n' ++#define DRV_VERSION "2.10" ++#define SYNTH_CLEAR '!' ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"CAPS_START\n" }}, ++ { CAPS_STOP, .u.s = {"CAPS_STOP\n" }}, ++ { RATE, .u.n = {"RATE %d\n", 8, 1, 16, 0, 0, NULL }}, ++ { PITCH, .u.n = {"PITCH %d\n", 8, 0, 16, 0, 0, NULL }}, ++ { VOL, .u.n = {"VOL %d\n", 8, 0, 16, 0, 0, NULL }}, ++ { TONE, .u.n = {"TONE %d\n", 8, 0, 16, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/dummy. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_dummy = { ++ .name = "dummy", ++ .version = DRV_VERSION, ++ .long_name = "Dummy", ++ .init = "Speakup\n", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "dummy", ++ }, ++}; ++ ++module_param_named(ser, synth_dummy.ser, int, S_IRUGO); ++module_param_named(start, synth_dummy.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init dummy_init(void) ++{ ++ return synth_add(&synth_dummy); ++} ++ ++static void __exit dummy_exit(void) ++{ ++ synth_remove(&synth_dummy); ++} ++ ++module_init(dummy_init); ++module_exit(dummy_exit); ++MODULE_AUTHOR("Samuel Thibault "); ++MODULE_DESCRIPTION("Speakup support for text console"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,124 @@ ++#ifndef _SPEAKUP_H ++#define _SPEAKUP_H ++#include ++ ++#include "spk_types.h" ++#include "i18n.h" ++ ++#define SPEAKUP_VERSION "3.1.3" ++#define KEY_MAP_VER 119 ++#define SHIFT_TBL_SIZE 64 ++#define MAX_DESC_LEN 72 ++ ++/* proc permissions */ ++#define USER_R (S_IFREG|S_IRUGO) ++#define USER_W (S_IFREG|S_IWUGO) ++#define USER_RW (S_IFREG|S_IRUGO|S_IWUGO) ++#define ROOT_W (S_IFREG|S_IRUGO|S_IWUSR) ++ ++#define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL } ++#define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL } ++#define MAXVARLEN 15 ++ ++#define SYNTH_OK 0x0001 ++#define B_ALPHA 0x0002 ++#define ALPHA 0x0003 ++#define B_CAP 0x0004 ++#define A_CAP 0x0007 ++#define B_NUM 0x0008 ++#define NUM 0x0009 ++#define ALPHANUM (B_ALPHA|B_NUM) ++#define SOME 0x0010 ++#define MOST 0x0020 ++#define PUNC 0x0040 ++#define A_PUNC 0x0041 ++#define B_WDLM 0x0080 ++#define WDLM 0x0081 ++#define B_EXNUM 0x0100 ++#define CH_RPT 0x0200 ++#define B_CTL 0x0400 ++#define A_CTL (B_CTL+SYNTH_OK) ++#define B_SYM 0x0800 ++#define B_CAPSYM (B_CAP|B_SYM) ++ ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) ++#define inverse_translate(vc, c) inverse_translate(vc, c, 0) ++#endif ++ ++#define IS_WDLM(x) (spk_chartab[((u_char)x)]&B_WDLM) ++#define IS_CHAR(x, type) (spk_chartab[((u_char)x)]&type) ++#define IS_TYPE(x, type) ((spk_chartab[((u_char)x)]&type) == type) ++ ++#define SET_DEFAULT -4 ++#define E_RANGE -3 ++#define E_TOOLONG -2 ++#define E_UNDEF -1 ++ ++extern int speakup_thread(void *data); ++extern void reset_default_chars(void); ++extern void reset_default_chartab(void); ++extern void synth_start(void); ++extern int set_key_info(const u_char *key_info, u_char *k_buffer); ++extern char *strlwr(char *s); ++extern char *speakup_s2i(char *start, int *dest); ++extern char *s2uchar(char *start, char *dest); ++extern char *xlate(char *s); ++extern int speakup_kobj_init(void); ++extern void speakup_kobj_exit(void); ++extern int chartab_get_value(char *keyword); ++extern void speakup_register_var(struct var_t *var); ++extern void speakup_unregister_var(enum var_id_t var_id); ++extern struct st_var_header *get_var_header(enum var_id_t var_id); ++extern struct st_var_header *var_header_by_name(const char *name); ++extern struct punc_var_t *get_punc_var(enum var_id_t var_id); ++extern int set_num_var(int val, struct st_var_header *var, int how); ++extern int set_string_var(const char *page, struct st_var_header *var, int len); ++extern int set_mask_bits(const char *input, const int which, const int how); ++extern special_func special_handler; ++extern int handle_help(struct vc_data *vc, u_char type, u_char ch, u_short key); ++extern int synth_init(char *name); ++extern void synth_release(void); ++ ++extern void do_flush(void); ++extern void speakup_start_ttys(void); ++extern void synth_buffer_add(char ch); ++extern void synth_buffer_clear(void); ++extern void speakup_clear_selection(void); ++extern int speakup_set_selection(struct tty_struct *tty); ++extern int speakup_paste_selection(struct tty_struct *tty); ++extern void speakup_register_devsynth(void); ++extern void speakup_unregister_devsynth(void); ++extern void synth_write(const char *buf, size_t count); ++extern int synth_supports_indexing(void); ++ ++extern struct vc_data *spk_sel_cons; ++extern unsigned short xs, ys, xe, ye; /* our region points */ ++ ++extern wait_queue_head_t speakup_event; ++extern struct kobject *speakup_kobj; ++extern struct task_struct *speakup_task; ++extern const u_char key_defaults[]; ++ ++/* Protect speakup synthesizer list */ ++extern struct mutex spk_mutex; ++extern struct st_spk_t *speakup_console[]; ++extern struct spk_synth *synth; ++extern char pitch_buff[]; ++extern u_char *our_keys[]; ++extern short punc_masks[]; ++extern char str_caps_start[], str_caps_stop[]; ++extern const struct st_bits_data punc_info[]; ++extern u_char key_buf[600]; ++extern char *characters[]; ++extern char *default_chars[]; ++extern u_short spk_chartab[]; ++extern int no_intr, say_ctrl, say_word_ctl, punc_level; ++extern int reading_punc, attrib_bleep, bleeps; ++extern int bleep_time, bell_pos; ++extern int spell_delay, key_echo; ++extern short punc_mask; ++extern short pitch_shift, synth_flags; ++extern int quiet_boot; ++extern char *synth_name; ++ ++#endif +--- a/drivers/staging/speakup/speakup_keypc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_keypc.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,323 @@ ++/* ++ * written by David Borowski ++ * ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * package it's not a general device driver. ++ * This driver is for the Keynote Gold internal synthesizer. ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.9" ++#define SYNTH_IO_EXTENT 0x04 ++#define SWAIT udelay(70) ++#define synth_writable() (inb_p(synth_port + UART_RX) & 0x10) ++#define synth_readable() (inb_p(synth_port + UART_RX) & 0x10) ++#define synth_full() ((inb_p(synth_port + UART_RX) & 0x80) == 0) ++#define PROCSPEECH 0x1f ++#define SYNTH_CLEAR 0x03 ++ ++static int synth_probe(struct spk_synth *synth); ++static void keynote_release(void); ++static const char *synth_immediate(struct spk_synth *synth, const char *buf); ++static void do_catch_up(struct spk_synth *synth); ++static void synth_flush(struct spk_synth *synth); ++ ++static int synth_port; ++static int port_forced; ++static unsigned int synth_portlist[] = { 0x2a8, 0 }; ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"[f130]" }}, ++ { CAPS_STOP, .u.s = {"[f90]" }}, ++ { RATE, .u.n = {"\04%c ", 8, 0, 10, 81, -8, NULL }}, ++ { PITCH, .u.n = {"[f%d]", 5, 0, 9, 40, 10, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/keypc. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_keypc = { ++ .name = "keypc", ++ .version = DRV_VERSION, ++ .long_name = "Keynote PC", ++ .init = "[t][n7,1][n8,0]", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 1000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = keynote_release, ++ .synth_immediate = synth_immediate, ++ .catch_up = do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_nop, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "keypc", ++ }, ++}; ++ ++static char *oops(void) ++{ ++ int s1, s2, s3, s4; ++ s1 = inb_p(synth_port); ++ s2 = inb_p(synth_port+1); ++ s3 = inb_p(synth_port+2); ++ s4 = inb_p(synth_port+3); ++ pr_warn("synth timeout %d %d %d %d\n", s1, s2, s3, s4); ++ return NULL; ++} ++ ++static const char *synth_immediate(struct spk_synth *synth, const char *buf) ++{ ++ u_char ch; ++ int timeout; ++ while ((ch = *buf)) { ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ if (synth_full()) ++ return buf; ++ timeout = 1000; ++ while (synth_writable()) ++ if (--timeout <= 0) ++ return oops(); ++ outb_p(ch, synth_port); ++ udelay(70); ++ buf++; ++ } ++ return 0; ++} ++ ++static void do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ int timeout; ++ unsigned long flags; ++ unsigned long jiff_max; ++ struct var_t *jiffy_delta; ++ struct var_t *delay_time; ++ struct var_t *full_time; ++ int delay_time_val; ++ int full_time_val; ++ int jiffy_delta_val; ++ ++ jiffy_delta = get_var(JIFFY); ++ delay_time = get_var(DELAY); ++ full_time = get_var(FULL); ++spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ ++ jiff_max = jiffies + jiffy_delta_val; ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ set_current_state(TASK_INTERRUPTIBLE); ++ full_time_val = full_time->u.n.value; ++ spk_unlock(flags); ++ if (synth_full()) { ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ continue; ++ } ++ set_current_state(TASK_RUNNING); ++ timeout = 1000; ++ while (synth_writable()) ++ if (--timeout <= 0) ++ break; ++ if (timeout <= 0) { ++ oops(); ++ break; ++ } ++ spk_lock(flags); ++ ch = synth_buffer_getc(); ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = PROCSPEECH; ++ outb_p(ch, synth_port); ++ SWAIT; ++ if ((jiffies >= jiff_max) && (ch == SPACE)) { ++ timeout = 1000; ++ while (synth_writable()) ++ if (--timeout <= 0) ++ break; ++ if (timeout <= 0) { ++ oops(); ++ break; ++ } ++ outb_p(PROCSPEECH, synth_port); ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ spk_unlock(flags); ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ jiff_max = jiffies+jiffy_delta_val; ++ } ++ } ++ timeout = 1000; ++ while (synth_writable()) ++ if (--timeout <= 0) ++ break; ++ if (timeout <= 0) ++ oops(); ++ else ++ outb_p(PROCSPEECH, synth_port); ++} ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ outb_p(SYNTH_CLEAR, synth_port); ++} ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ unsigned int port_val = 0; ++ int i = 0; ++ pr_info("Probing for %s.\n", synth->long_name); ++ if (port_forced) { ++ synth_port = port_forced; ++ pr_info("probe forced to %x by kernel command line\n", ++ synth_port); ++ if (synth_request_region(synth_port-1, SYNTH_IO_EXTENT)) { ++ pr_warn("sorry, port already reserved\n"); ++ return -EBUSY; ++ } ++ port_val = inb(synth_port); ++ } else { ++ for (i = 0; synth_portlist[i]; i++) { ++ if (synth_request_region(synth_portlist[i], ++ SYNTH_IO_EXTENT)) { ++ pr_warn("request_region: failed with 0x%x, %d\n", ++ synth_portlist[i], SYNTH_IO_EXTENT); ++ continue; ++ } ++ port_val = inb(synth_portlist[i]); ++ if (port_val == 0x80) { ++ synth_port = synth_portlist[i]; ++ break; ++ } ++ } ++ } ++ if (port_val != 0x80) { ++ pr_info("%s: not found\n", synth->long_name); ++ synth_release_region(synth_portlist[i], SYNTH_IO_EXTENT); ++ synth_port = 0; ++ return -ENODEV; ++ } ++ pr_info("%s: %03x-%03x, driver version %s,\n", synth->long_name, ++ synth_port, synth_port+SYNTH_IO_EXTENT-1, ++ synth->version); ++ synth->alive = 1; ++ return 0; ++} ++ ++static void keynote_release(void) ++{ ++ if (synth_port) ++ synth_release_region(synth_port, SYNTH_IO_EXTENT); ++ synth_port = 0; ++} ++ ++module_param_named(port, port_forced, int, S_IRUGO); ++module_param_named(start, synth_keypc.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(port, "Set the port for the synthesizer (override probing)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init keypc_init(void) ++{ ++ return synth_add(&synth_keypc); ++} ++ ++static void __exit keypc_exit(void) ++{ ++ synth_remove(&synth_keypc); ++} ++ ++module_init(keypc_init); ++module_exit(keypc_exit); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Keynote Gold PC synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_ltlk.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_ltlk.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,191 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include "speakup.h" ++#include "spk_priv.h" ++#include "serialio.h" ++#include "speakup_dtlk.h" /* local header file for LiteTalk values */ ++ ++#define DRV_VERSION "2.10" ++#define synth_full( ) ( !( inb( synth_port_tts + UART_MSR ) & UART_MSR_CTS ) ) ++#define PROCSPEECH 0x0d ++ ++static int synth_probe(struct spk_synth *synth); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x01+35p" }}, ++ { CAPS_STOP, .u.s = {"\x01-35p" }}, ++ { RATE, .u.n = {"\x01%ds", 8, 0, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x01%dp", 50, 0, 99, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }}, ++ { PUNCT, .u.n = {"\x01%db", 7, 0, 15, 0, 0, NULL }}, ++ { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }}, ++ { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/ltlk. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute freq_attribute = ++ __ATTR(freq, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &freq_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_ltlk = { ++ .name = "ltlk", ++ .version = DRV_VERSION, ++ .long_name = "LiteTalk", ++ .init = "\01@\x01\x31y\n\0", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = spk_serial_in_nowait, ++ .indexing = { ++ .command = "\x01%di", ++ .lowindex = 1, ++ .highindex = 5, ++ .currindex = 1, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "ltlk", ++ }, ++}; ++ ++/* interrogate the LiteTalk and print its settings */ ++static void synth_interrogate(struct spk_synth *synth) ++{ ++ unsigned char *t, i; ++ unsigned char buf[50], rom_v[20]; ++ spk_synth_immediate(synth, "\x18\x01?"); ++ for (i = 0; i < 50; i++) { ++ buf[i] = spk_serial_in(); ++ if (i > 2 && buf[i] == 0x7f) ++ break; ++ } ++ t = buf+2; ++ for (i = 0; *t != '\r'; t++) { ++ rom_v[i] = *t; ++ if (++i >= 19) ++ break; ++ } ++ rom_v[i] = 0; ++ pr_info("%s: ROM version: %s\n", synth->long_name, rom_v); ++} ++ ++static int synth_probe(struct spk_synth *synth) ++{ ++ int failed = 0; ++ ++ failed = serial_synth_probe(synth); ++ if (failed == 0) ++ synth_interrogate(synth); ++ synth->alive = !failed; ++ return failed; ++} ++ ++module_param_named(ser, synth_ltlk.ser, int, S_IRUGO); ++module_param_named(start, synth_ltlk.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init ltlk_init(void) ++{ ++ return synth_add(&synth_ltlk); ++} ++ ++static void __exit ltlk_exit(void) ++{ ++ synth_remove(&synth_ltlk); ++} ++ ++module_init(ltlk_init); ++module_exit(ltlk_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for DoubleTalk LT/LiteTalk synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakupmap.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakupmap.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,65 @@ ++ 119, 62, 6, ++ 0, 16, 20, 17, 32, 48, 0, ++ 2, 0, 78, 0, 0, 0, 0, ++ 3, 0, 79, 0, 0, 0, 0, ++ 4, 0, 76, 0, 0, 0, 0, ++ 5, 0, 77, 0, 0, 0, 0, ++ 6, 0, 74, 0, 0, 0, 0, ++ 7, 0, 75, 0, 0, 0, 0, ++ 9, 0, 5, 46, 0, 0, 0, ++ 10, 0, 4, 0, 0, 0, 0, ++ 11, 0, 0, 1, 0, 0, 0, ++ 12, 0, 27, 0, 33, 0, 0, ++ 19, 0, 47, 0, 0, 0, 0, ++ 21, 0, 29, 17, 0, 0, 0, ++ 22, 0, 15, 0, 0, 0, 0, ++ 23, 0, 14, 0, 0, 0, 28, ++ 24, 0, 16, 0, 0, 0, 0, ++ 25, 0, 30, 18, 0, 0, 0, ++ 28, 0, 3, 26, 0, 0, 0, ++ 35, 0, 31, 0, 0, 0, 0, ++ 36, 0, 12, 0, 0, 0, 0, ++ 37, 0, 11, 0, 0, 0, 22, ++ 38, 0, 13, 0, 0, 0, 0, ++ 39, 0, 32, 7, 0, 0, 0, ++ 40, 0, 23, 0, 0, 0, 0, ++ 44, 0, 44, 0, 0, 0, 0, ++ 49, 0, 24, 0, 0, 0, 0, ++ 50, 0, 9, 19, 6, 0, 0, ++ 51, 0, 8, 0, 0, 0, 36, ++ 52, 0, 10, 20, 0, 0, 0, ++ 53, 0, 25, 0, 0, 0, 0, ++ 55, 46, 1, 0, 0, 0, 0, ++ 58, 128, 128, 0, 0, 0, 0, ++ 59, 0, 45, 0, 0, 0, 0, ++ 60, 0, 40, 0, 0, 0, 0, ++ 61, 0, 41, 0, 0, 0, 0, ++ 62, 0, 42, 0, 0, 0, 0, ++ 63, 0, 34, 0, 0, 0, 0, ++ 64, 0, 35, 0, 0, 0, 0, ++ 65, 0, 37, 0, 0, 0, 0, ++ 66, 0, 38, 0, 0, 0, 0, ++ 67, 0, 66, 0, 39, 0, 0, ++ 68, 0, 67, 0, 0, 0, 0, ++ 71, 15, 19, 0, 0, 0, 0, ++ 72, 14, 29, 0, 0, 28, 0, ++ 73, 16, 17, 0, 0, 0, 0, ++ 74, 27, 33, 0, 0, 0, 0, ++ 75, 12, 31, 0, 0, 0, 0, ++ 76, 11, 21, 0, 0, 22, 0, ++ 77, 13, 32, 0, 0, 0, 0, ++ 78, 23, 43, 0, 0, 0, 0, ++ 79, 9, 20, 0, 0, 0, 0, ++ 80, 8, 30, 0, 0, 36, 0, ++ 81, 10, 18, 0, 0, 0, 0, ++ 82, 128, 128, 0, 0, 0, 0, ++ 83, 24, 25, 0, 0, 0, 0, ++ 87, 0, 68, 0, 0, 0, 0, ++ 88, 0, 69, 0, 0, 0, 0, ++ 96, 3, 26, 0, 0, 0, 0, ++ 98, 4, 5, 0, 0, 0, 0, ++ 99, 2, 0, 0, 0, 0, 0, ++ 104, 0, 6, 0, 0, 0, 0, ++ 109, 0, 7, 0, 0, 0, 0, ++ 125, 128, 128, 0, 0, 0, 0, ++ 0, 119 +--- a/drivers/staging/speakup/speakupmap.map 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakupmap.map 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,93 @@ ++spk key_f9 = punc_level_dec ++spk key_f10 = punc_level_inc ++spk key_f11 = reading_punc_dec ++spk key_f12 = reading_punc_inc ++spk key_1 = vol_dec ++spk key_2 = vol_inc ++spk key_3 = pitch_dec ++spk key_4 = pitch_inc ++spk key_5 = rate_dec ++spk key_6 = rate_inc ++key_kpasterisk = toggle_cursoring ++ctrl spk key_8 = toggle_cursoring ++spk key_kpasterisk = speakup_goto ++spk key_f1 = speakup_help ++spk key_f2 = set_win ++spk key_f3 = clear_win ++spk key_f4 = enable_win ++spk key_f5 = edit_some ++spk key_f6 = edit_most ++spk key_f7 = edit_delim ++spk key_f8 = edit_repeat ++shift spk key_f9 = edit_exnum ++ key_kp7 = say_prev_line ++spk key_kp7 = left_edge ++ key_kp8 = say_line ++double key_kp8 = say_line_indent ++spk key_kp8 = say_from_top ++ key_kp9 = say_next_line ++spk key_kp9 = top_edge ++ key_kpminus = speakup_parked ++spk key_kpminus = say_char_num ++ key_kp4 = say_prev_word ++spk key_kp4 = say_from_left ++ key_kp5 = say_word ++double key_kp5 = spell_word ++spk key_kp5 = spell_phonetic ++ key_kp6 = say_next_word ++spk key_kp6 = say_to_right ++ key_kpplus = say_screen ++spk key_kpplus = say_win ++ key_kp1 = say_prev_char ++spk key_kp1 = right_edge ++ key_kp2 = say_char ++spk key_kp2 = say_to_bottom ++double key_kp2 = say_phonetic_char ++ key_kp3 = say_next_char ++spk key_kp3 = bottom_edge ++ key_kp0 = spk_key ++ key_kpdot = say_position ++spk key_kpdot = say_attributes ++key_kpenter = speakup_quiet ++spk key_kpenter = speakup_off ++key_sysrq = speech_kill ++ key_kpslash = speakup_cut ++spk key_kpslash = speakup_paste ++spk key_pageup = say_first_char ++spk key_pagedown = say_last_char ++key_capslock = spk_key ++ spk key_z = spk_lock ++key_leftmeta = spk_key ++ctrl spk key_0 = speakup_goto ++spk key_u = say_prev_line ++spk key_i = say_line ++double spk key_i = say_line_indent ++spk key_o = say_next_line ++spk key_minus = speakup_parked ++shift spk key_minus = say_char_num ++spk key_j = say_prev_word ++spk key_k = say_word ++double spk key_k = spell_word ++spk key_l = say_next_word ++spk key_m = say_prev_char ++spk key_comma = say_char ++double spk key_comma = say_phonetic_char ++spk key_dot = say_next_char ++spk key_n = say_position ++ ctrl spk key_m = left_edge ++ ctrl spk key_y = top_edge ++ ctrl spk key_dot = right_edge ++ctrl spk key_p = bottom_edge ++spk key_apostrophe = say_screen ++spk key_h = say_from_left ++spk key_y = say_from_top ++spk key_semicolon = say_to_right ++spk key_p = say_to_bottom ++spk key_slash = say_attributes ++ spk key_enter = speakup_quiet ++ ctrl spk key_enter = speakup_off ++ spk key_9 = speakup_cut ++spk key_8 = speakup_paste ++shift spk key_m = say_first_char ++ ctrl spk key_semicolon = say_last_char ++spk key_r = read_all_doc +--- a/drivers/staging/speakup/speakup_soft.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_soft.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,365 @@ ++/* speakup_soft.c - speakup driver to register and make available ++ * a user space device for software synthesizers. written by: Kirk ++ * Reiser ++ * ++ * Copyright (C) 2003 Kirk Reiser. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * this code is specificly written as a driver for the speakup screenreview ++ * package and is not a general device driver. */ ++ ++#include ++#include /* for misc_register, and SYNTH_MINOR */ ++#include /* for poll_wait() */ ++ ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.6" ++#define SOFTSYNTH_MINOR 26 /* might as well give it one more than /dev/synth */ ++#define PROCSPEECH 0x0d ++#define CLEAR_SYNTH 0x18 ++ ++static int softsynth_probe(struct spk_synth *synth); ++static void softsynth_release(void); ++static int softsynth_is_alive(struct spk_synth *synth); ++static unsigned char get_index(void); ++ ++static struct miscdevice synth_device; ++static int initialized = 0; ++static int misc_registered; ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x01+3p" }}, ++ { CAPS_STOP, .u.s = {"\x01-3p" }}, ++ { RATE, .u.n = {"\x01%ds", 5, 0, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL }}, ++ { PUNCT, .u.n = {"\x01%db", 0, 0, 2, 0, 0, NULL }}, ++ { VOICE, .u.n = {"\x01%do", 0, 0, 7, 0, 0, NULL }}, ++ { FREQUENCY, .u.n = {"\x01%df", 5, 0, 9, 0, 0, NULL }}, ++ { DIRECT, .u.n = {NULL, 0, 0, 1, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/soft. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute freq_attribute = ++ __ATTR(freq, USER_RW, spk_var_show, spk_var_store); ++//static struct kobj_attribute lang_attribute = ++// __ATTR(lang, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute voice_attribute = ++ __ATTR(voice, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute direct_attribute = ++ __ATTR(direct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &freq_attribute.attr, ++// &lang_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &voice_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &direct_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_soft = { ++ .name = "soft", ++ .version = DRV_VERSION, ++ .long_name = "software synth", ++ .init = "\01@\x01\x31y\n", ++ .procspeech = PROCSPEECH, ++ .delay = 0, ++ .trigger = 0, ++ .jiffies = 0, ++ .full = 0, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = softsynth_probe, ++ .release = softsynth_release, ++ .synth_immediate = NULL, ++ .catch_up = NULL, ++ .flush = NULL, ++ .is_alive = softsynth_is_alive, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = get_index, ++ .indexing = { ++ .command = "\x01%di", ++ .lowindex = 1, ++ .highindex = 5, ++ .currindex = 1, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "soft", ++ }, ++}; ++ ++static char *get_initstring(void) ++{ ++ static char buf[40]; ++ char *cp; ++ struct var_t *var; ++ ++ memset(buf, 0, sizeof(buf)); ++ cp = buf; ++ var = synth_soft.vars; ++ while (var->var_id != MAXVARS) { ++ if (var->var_id != CAPS_START && var->var_id != CAPS_STOP ++ && var->var_id != DIRECT) ++ cp = cp + sprintf(cp, var->u.n.synth_fmt, var->u.n.value); ++ var++; ++ } ++ cp = cp + sprintf(cp, "\n"); ++ return buf; ++} ++ ++static int softsynth_open(struct inode *inode, struct file *fp) ++{ ++ unsigned long flags; ++ /*if ((fp->f_flags & O_ACCMODE) != O_RDONLY) */ ++ /* return -EPERM; */ ++ spk_lock(flags); ++ if (synth_soft.alive) { ++ spk_unlock(flags); ++ return -EBUSY; ++ } ++ synth_soft.alive = 1; ++ spk_unlock(flags); ++ return 0; ++} ++ ++static int softsynth_close(struct inode *inode, struct file *fp) ++{ ++ unsigned long flags; ++ spk_lock(flags); ++ synth_soft.alive = 0; ++ initialized = 0; ++ spk_unlock(flags); ++ /* Make sure we let applications go before leaving */ ++ speakup_start_ttys(); ++ return 0; ++} ++ ++static ssize_t softsynth_read(struct file *fp, char *buf, size_t count, ++ loff_t *pos) ++{ ++ int chars_sent = 0; ++ char *cp; ++ char *init; ++ char ch; ++ int empty; ++ unsigned long flags; ++ DEFINE_WAIT(wait); ++ ++ spk_lock(flags); ++ while (1) { ++ prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); ++ if (!synth_buffer_empty() || speakup_info.flushing) ++ break; ++ spk_unlock(flags); ++ if (fp->f_flags & O_NONBLOCK) { ++ finish_wait(&speakup_event, &wait); ++ return -EAGAIN; ++ } ++ if (signal_pending(current)) { ++ finish_wait(&speakup_event, &wait); ++ return -ERESTARTSYS; ++ } ++ schedule(); ++ spk_lock(flags); ++ } ++ finish_wait(&speakup_event, &wait); ++ ++ cp = buf; ++ init = get_initstring(); ++ while (chars_sent < count) { ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ ch = '\x18'; ++ } else if (synth_buffer_empty()) { ++ break; ++ } else if (! initialized) { ++ if (*init) { ++ ch = *init; ++ init++; ++ } else { ++ initialized = 1; ++ } ++ } else { ++ ch = synth_buffer_getc(); ++ } ++ spk_unlock(flags); ++ if (copy_to_user(cp, &ch, 1)) ++ return -EFAULT; ++ spk_lock(flags); ++ chars_sent++; ++ cp++; ++ } ++ *pos += chars_sent; ++ empty = synth_buffer_empty(); ++ spk_unlock(flags); ++ if (empty) { ++ speakup_start_ttys(); ++ *pos = 0; ++ } ++ return chars_sent; ++} ++ ++static int last_index = 0; ++ ++static ssize_t softsynth_write(struct file *fp, const char *buf, size_t count, ++ loff_t *pos) ++{ ++ char indbuf[5]; ++ if (count >= sizeof(indbuf)) ++ return -EINVAL; ++ ++ if (copy_from_user(indbuf, buf, count)) ++ return -EFAULT; ++ indbuf[4] = 0; ++ ++ last_index = simple_strtoul(indbuf, NULL, 0); ++ return count; ++} ++ ++static unsigned int softsynth_poll(struct file *fp, ++ struct poll_table_struct *wait) ++{ ++ unsigned long flags; ++ int ret = 0; ++ poll_wait(fp, &speakup_event, wait); ++ ++ spk_lock(flags); ++ if (! synth_buffer_empty() || speakup_info.flushing) ++ ret = POLLIN | POLLRDNORM; ++ spk_unlock(flags); ++ return ret; ++} ++ ++static unsigned char get_index(void) ++{ ++ int rv; ++ rv = last_index; ++ last_index = 0; ++ return rv; ++} ++ ++static struct file_operations softsynth_fops = { ++ .owner = THIS_MODULE, ++ .poll = softsynth_poll, ++ .read = softsynth_read, ++ .write = softsynth_write, ++ .open = softsynth_open, ++ .release = softsynth_close, ++}; ++ ++ ++static int softsynth_probe(struct spk_synth *synth) ++{ ++ ++ if (misc_registered != 0) ++ return 0; ++ memset(&synth_device, 0, sizeof(synth_device)); ++ synth_device.minor = SOFTSYNTH_MINOR; ++ synth_device.name = "softsynth"; ++ synth_device.fops = &softsynth_fops; ++ if (misc_register(&synth_device)) { ++ pr_warn("Couldn't initialize miscdevice /dev/softsynth.\n"); ++ return -ENODEV; ++ } ++ ++ misc_registered = 1; ++ pr_info("initialized device: /dev/softsynth, node (MAJOR 10, MINOR 26)\n"); ++ return 0; ++} ++ ++static void softsynth_release(void) ++{ ++ misc_deregister(&synth_device); ++ misc_registered = 0; ++ pr_info("unregistered /dev/softsynth\n"); ++} ++ ++static int softsynth_is_alive(struct spk_synth *synth) ++{ ++ if (synth_soft.alive) ++ return 1; ++ return 0; ++} ++ ++module_param_named(start, synth_soft.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++ ++static int __init soft_init(void) ++{ ++ return synth_add(&synth_soft); ++} ++ ++static void __exit soft_exit(void) ++{ ++ synth_remove(&synth_soft); ++} ++ ++module_init(soft_init); ++module_exit(soft_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_DESCRIPTION("Speakup userspace software synthesizer support"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_spkout.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_spkout.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,161 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include "spk_priv.h" ++#include "speakup.h" ++#include "serialio.h" ++ ++#define DRV_VERSION "2.10" ++#define SYNTH_CLEAR 0x18 ++#define PROCSPEECH '\r' ++ ++static void synth_flush(struct spk_synth *synth); ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x05P+" }}, ++ { CAPS_STOP, .u.s = {"\x05P-" }}, ++ { RATE, .u.n = {"\x05R%d", 7, 0, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x05P%d", 3, 0, 9, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x05V%d", 9, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x05T%c", 8, 0, 25, 65, 0, NULL }}, ++ { PUNCT, .u.n = {"\x05M%c", 0, 0, 3, 0, 0, "nsma" }}, ++ V_LAST_VAR ++}; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/spkout. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute punct_attribute = ++ __ATTR(punct, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &punct_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_spkout = { ++ .name = "spkout", ++ .version = DRV_VERSION, ++ .long_name = "Speakout", ++ .init = "\005W1\005I2\005C3", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = spk_serial_in_nowait, ++ .indexing = { ++ .command = "\x05[%c", ++ .lowindex = 1, ++ .highindex = 5, ++ .currindex = 1, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "spkout", ++ }, ++}; ++ ++static void synth_flush(struct spk_synth *synth) ++{ ++ int timeout = SPK_XMITR_TIMEOUT; ++ while (spk_serial_tx_busy()) { ++ if (!--timeout) ++ break; ++ udelay(1); ++ } ++ outb(SYNTH_CLEAR, speakup_info.port_tts); ++} ++ ++module_param_named(ser, synth_spkout.ser, int, S_IRUGO); ++module_param_named(start, synth_spkout.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init spkout_init(void) ++{ ++ return synth_add(&synth_spkout); ++} ++ ++static void __exit spkout_exit(void) ++{ ++ synth_remove(&synth_spkout); ++} ++ ++module_init(spkout_init); ++module_exit(spkout_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Speak Out synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/speakup_txprt.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/speakup_txprt.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,143 @@ ++/* ++ * originally written by: Kirk Reiser ++* this version considerably modified by David Borowski, david575@rogers.com ++ * ++ * Copyright (C) 1998-99 Kirk Reiser. ++ * Copyright (C) 2003 David Borowski. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ * ++ * specificly written as a driver for the speakup screenreview ++ * s not a general device driver. ++ */ ++#include "spk_priv.h" ++#include "speakup.h" ++ ++#define DRV_VERSION "2.10" ++#define SYNTH_CLEAR 0x18 ++#define PROCSPEECH '\r' /* process speech char */ ++ ++static struct var_t vars[] = { ++ { CAPS_START, .u.s = {"\x05P8" }}, ++ { CAPS_STOP, .u.s = {"\x05P5" }}, ++ { RATE, .u.n = {"\x05R%d", 5, 0, 9, 0, 0, NULL }}, ++ { PITCH, .u.n = {"\x05P%d", 5, 0, 9, 0, 0, NULL }}, ++ { VOL, .u.n = {"\x05V%d", 5, 0, 9, 0, 0, NULL }}, ++ { TONE, .u.n = {"\x05T%c", 12, 0, 25, 61, 0, NULL }}, ++ V_LAST_VAR ++ }; ++ ++/* ++ * These attributes will appear in /sys/accessibility/speakup/txprt. ++ */ ++static struct kobj_attribute caps_start_attribute = ++ __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute caps_stop_attribute = ++ __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute pitch_attribute = ++ __ATTR(pitch, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute rate_attribute = ++ __ATTR(rate, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute tone_attribute = ++ __ATTR(tone, USER_RW, spk_var_show, spk_var_store); ++static struct kobj_attribute vol_attribute = ++ __ATTR(vol, USER_RW, spk_var_show, spk_var_store); ++ ++static struct kobj_attribute delay_time_attribute = ++ __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute full_time_attribute = ++ __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute jiffy_delta_attribute = ++ __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store); ++static struct kobj_attribute trigger_time_attribute = ++ __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store); ++ ++/* ++ * Create a group of attributes so that we can create and destroy them all ++ * at once. ++ */ ++static struct attribute *synth_attrs[] = { ++ &caps_start_attribute.attr, ++ &caps_stop_attribute.attr, ++ &pitch_attribute.attr, ++ &rate_attribute.attr, ++ &tone_attribute.attr, ++ &vol_attribute.attr, ++ &delay_time_attribute.attr, ++ &full_time_attribute.attr, ++ &jiffy_delta_attribute.attr, ++ &trigger_time_attribute.attr, ++ NULL, /* need to NULL terminate the list of attributes */ ++}; ++ ++static struct spk_synth synth_txprt = { ++ .name = "txprt", ++ .version = DRV_VERSION, ++ .long_name = "Transport", ++ .init = "\x05N1", ++ .procspeech = PROCSPEECH, ++ .clear = SYNTH_CLEAR, ++ .delay = 500, ++ .trigger = 50, ++ .jiffies = 50, ++ .full = 40000, ++ .startup = SYNTH_START, ++ .checkval = SYNTH_CHECK, ++ .vars = vars, ++ .probe = serial_synth_probe, ++ .release = spk_serial_release, ++ .synth_immediate = spk_synth_immediate, ++ .catch_up = spk_do_catch_up, ++ .flush = spk_synth_flush, ++ .is_alive = spk_synth_is_alive_restart, ++ .synth_adjust = NULL, ++ .read_buff_add = NULL, ++ .get_index = NULL, ++ .indexing = { ++ .command = NULL, ++ .lowindex = 0, ++ .highindex = 0, ++ .currindex = 0, ++ }, ++ .attributes = { ++ .attrs = synth_attrs, ++ .name = "txprt", ++ }, ++}; ++ ++module_param_named(ser, synth_txprt.ser, int, S_IRUGO); ++module_param_named(start, synth_txprt.startup, short, S_IRUGO); ++ ++MODULE_PARM_DESC(ser, "Set the serial port for the synthesizer (0-based)."); ++MODULE_PARM_DESC(start, "Start the synthesizer once it is loaded."); ++ ++static int __init txprt_init(void) ++{ ++ return synth_add(&synth_txprt); ++} ++ ++static void __exit txprt_exit(void) ++{ ++ synth_remove(&synth_txprt); ++} ++ ++module_init(txprt_init); ++module_exit(txprt_exit); ++MODULE_AUTHOR("Kirk Reiser "); ++MODULE_AUTHOR("David Borowski"); ++MODULE_DESCRIPTION("Speakup support for Transport synthesizers"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ +--- a/drivers/staging/speakup/spk_priv.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/spk_priv.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,93 @@ ++/* spk_priv.h ++ 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. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++#ifndef _SPEAKUP_PRIVATE_H ++#define _SPEAKUP_PRIVATE_H ++ ++#include "spk_types.h" ++#include "spk_priv_keyinfo.h" ++ ++#ifndef pr_warn ++#define pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg) ++#endif ++ ++#define V_LAST_VAR { MAXVARS } ++#define SPACE 0x20 ++#define SYNTH_CHECK 20030716 /* today's date ought to do for check value */ ++/* synth flags, for odd synths */ ++#define SF_DEC 1 /* to fiddle puncs in alpha strings so it doesn't spell */ ++#ifdef MODULE ++#define SYNTH_START 1 ++#else ++#define SYNTH_START 0 ++#endif ++ ++#define KT_SPKUP 15 ++ ++extern struct serial_state *spk_serial_init(int index); ++extern void stop_serial_interrupt(void); ++extern int wait_for_xmitr(void); ++extern unsigned char spk_serial_in(void); ++extern unsigned char spk_serial_in_nowait(void); ++extern int spk_serial_out(const char ch); ++extern void spk_serial_release(void); ++ ++extern char synth_buffer_getc(void); ++extern char synth_buffer_peek(void); ++extern int synth_buffer_empty(void); ++extern struct var_t *get_var(enum var_id_t var_id); ++extern ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr, ++ char *buf); ++extern ssize_t spk_var_store(struct kobject *kobj, struct kobj_attribute *attr, ++ const char *buf, size_t count); ++ ++extern int serial_synth_probe(struct spk_synth *synth); ++extern const char *spk_synth_immediate(struct spk_synth *synth, const char *buff); ++extern void spk_do_catch_up(struct spk_synth *synth); ++extern void spk_synth_flush(struct spk_synth *synth); ++extern int spk_synth_is_alive_nop(struct spk_synth *synth); ++extern int spk_synth_is_alive_restart(struct spk_synth *synth); ++extern void synth_printf(const char *buf, ...); ++extern int synth_request_region(u_long, u_long); ++extern int synth_release_region(u_long, u_long); ++extern int synth_add(struct spk_synth *in_synth); ++extern void synth_remove(struct spk_synth *in_synth); ++ ++extern struct speakup_info_t speakup_info; ++ ++extern struct var_t synth_time_vars[]; ++ ++/* Protect the whole speakup machinery, must be taken at each kernel->speakup ++ * transition and released at all corresponding speakup->kernel transitions ++ * (flags must be the same variable between lock/trylock and unlock). ++ * ++ * The progression thread only interferes with the speakup machinery through ++ * the synth buffer, and so only needs to take the lock while tinkering with ++ * it. ++ */ ++/* Speakup needs to disable the keyboard IRQ, hence _irqsave/restore */ ++#define spk_lock(flags) spin_lock_irqsave(&speakup_info.spinlock, flags) ++#define spk_trylock(flags) spin_trylock_irqsave(&speakup_info.spinlock, flags) ++#define spk_unlock(flags) spin_unlock_irqrestore(&speakup_info.spinlock, flags) ++ ++#endif +--- a/drivers/staging/speakup/spk_priv_keyinfo.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/spk_priv_keyinfo.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,110 @@ ++/* spk_priv.h ++ 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. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++*/ ++ ++#ifndef _SPEAKUP_KEYINFO_H ++#define _SPEAKUP_KEYINFO_H ++ ++#define FIRST_SYNTH_VAR RATE ++/* 0 is reserved for no remap */ ++#define SPEAKUP_GOTO 0x01 ++#define SPEECH_KILL 0x02 ++#define SPEAKUP_QUIET 0x03 ++#define SPEAKUP_CUT 0x04 ++#define SPEAKUP_PASTE 0x05 ++#define SAY_FIRST_CHAR 0x06 ++#define SAY_LAST_CHAR 0x07 ++#define SAY_CHAR 0x08 ++#define SAY_PREV_CHAR 0x09 ++#define SAY_NEXT_CHAR 0x0a ++#define SAY_WORD 0x0b ++#define SAY_PREV_WORD 0x0c ++#define SAY_NEXT_WORD 0x0d ++#define SAY_LINE 0x0e ++#define SAY_PREV_LINE 0x0f ++#define SAY_NEXT_LINE 0x10 ++#define TOP_EDGE 0x11 ++#define BOTTOM_EDGE 0x12 ++#define LEFT_EDGE 0x13 ++#define RIGHT_EDGE 0x14 ++#define SPELL_PHONETIC 0x15 ++#define SPELL_WORD 0x16 ++#define SAY_SCREEN 0x17 ++#define SAY_POSITION 0x18 ++#define SAY_ATTRIBUTES 0x19 ++#define SPEAKUP_OFF 0x1a ++#define SPEAKUP_PARKED 0x1b ++#define SAY_LINE_INDENT 0x1c ++#define SAY_FROM_TOP 0x1d ++#define SAY_TO_BOTTOM 0x1e ++#define SAY_FROM_LEFT 0x1f ++#define SAY_TO_RIGHT 0x20 ++#define SAY_CHAR_NUM 0x21 ++#define EDIT_SOME 0x22 ++#define EDIT_MOST 0x23 ++#define SAY_PHONETIC_CHAR 0x24 ++#define EDIT_DELIM 0x25 ++#define EDIT_REPEAT 0x26 ++#define EDIT_EXNUM 0x27 ++#define SET_WIN 0x28 ++#define CLEAR_WIN 0x29 ++#define ENABLE_WIN 0x2a ++#define SAY_WIN 0x2b ++#define SPK_LOCK 0x2c ++#define SPEAKUP_HELP 0x2d ++#define TOGGLE_CURSORING 0x2e ++#define READ_ALL_DOC 0x2f ++#define SPKUP_MAX_FUNC 0x30 /* one greater than the last func handler */ ++ ++#define SPK_KEY 0x80 ++#define FIRST_EDIT_BITS 0x22 ++ ++#define FIRST_SET_VAR SPELL_DELAY ++#define VAR_START 0x40 /* increase if adding more than 0x3f functions */ ++ ++/* keys for setting variables, must be ordered same as the enum for var_ids */ ++/* with dec being even and inc being 1 greater */ ++#define SPELL_DELAY_DEC VAR_START+0 ++#define SPELL_DELAY_INC SPELL_DELAY_DEC+1 ++#define PUNC_LEVEL_DEC SPELL_DELAY_DEC+2 ++#define PUNC_LEVEL_INC PUNC_LEVEL_DEC+1 ++#define READING_PUNC_DEC PUNC_LEVEL_DEC+2 ++#define READING_PUNC_INC READING_PUNC_DEC+1 ++#define ATTRIB_BLEEP_DEC READING_PUNC_DEC+2 ++#define ATTRIB_BLEEP_INC ATTRIB_BLEEP_DEC+1 ++#define BLEEPS_DEC ATTRIB_BLEEP_DEC+2 ++#define BLEEPS_INC BLEEPS_DEC+1 ++#define RATE_DEC BLEEPS_DEC+2 ++#define RATE_INC RATE_DEC+1 ++#define PITCH_DEC RATE_DEC+2 ++#define PITCH_INC PITCH_DEC+1 ++#define VOL_DEC PITCH_DEC+2 ++#define VOL_INC VOL_DEC+1 ++#define TONE_DEC VOL_DEC+2 ++#define TONE_INC TONE_DEC+1 ++#define PUNCT_DEC TONE_DEC+2 ++#define PUNCT_INC PUNCT_DEC+1 ++#define VOICE_DEC PUNCT_DEC+2 ++#define VOICE_INC VOICE_DEC+1 ++ ++#endif +--- a/drivers/staging/speakup/spk_types.h 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/spk_types.h 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,185 @@ ++#ifndef SPEAKUP_TYPES_H ++#define SPEAKUP_TYPES_H ++ ++/* ++ * This file includes all of the typedefs and structs used in speakup. ++ */ ++ ++#include ++#include ++#include ++#include ++#include /* for wait_queue */ ++#include /* for __init */ ++#include ++#include ++#include ++#include ++#include /* for inb_p, outb_p, inb, outb, etc... */ ++ ++enum var_type_t { ++ VAR_NUM = 0, ++ VAR_TIME, ++ VAR_STRING, ++ VAR_PROC ++}; ++ ++enum { ++ E_DEFAULT = 0, ++ E_SET, ++ E_INC, ++ E_DEC ++}; ++ ++enum var_id_t { ++ VERSION = 0, SYNTH, SILENT, SYNTH_DIRECT, ++ KEYMAP, CHARS, ++ PUNC_SOME, PUNC_MOST, PUNC_ALL, ++ DELIM, REPEATS, EXNUMBER, ++ DELAY, TRIGGER, JIFFY, FULL, /* all timers must be together */ ++ BLEEP_TIME, CURSOR_TIME, BELL_POS, ++SAY_CONTROL, SAY_WORD_CTL, NO_INTERRUPT, KEY_ECHO, ++ SPELL_DELAY, PUNC_LEVEL, READING_PUNC, ++ ATTRIB_BLEEP, BLEEPS, ++ RATE, PITCH, VOL, TONE, PUNCT, VOICE, FREQUENCY, LANG, DIRECT, ++ CAPS_START, CAPS_STOP, CHARTAB, ++ MAXVARS ++}; ++ ++typedef int (*special_func)(struct vc_data *vc, u_char type, u_char ch, ++ u_short key); ++ ++#define COLOR_BUFFER_SIZE 160 ++ ++struct spk_highlight_color_track{ ++ /* Count of each background color */ ++ unsigned int bgcount[8]; ++ /* Buffer for characters drawn with each background color */ ++ char highbuf[8][COLOR_BUFFER_SIZE]; ++ /* Current index into highbuf */ ++ unsigned int highsize[8]; ++ /* Reading Position for each color */ ++ u_long rpos[8], rx[8], ry[8]; ++ /* Real Cursor Y Position */ ++ ulong cy; ++}; ++ ++struct st_spk_t { ++ u_long reading_x, cursor_x; ++ u_long reading_y, cursor_y; ++ u_long reading_pos, cursor_pos; ++ u_long go_x, go_pos; ++ u_long w_top, w_bottom, w_left, w_right; ++ u_char w_start, w_enabled; ++ u_char reading_attr, old_attr; ++ char parked, shut_up; ++ struct spk_highlight_color_track ht; ++ int tty_stopped; ++}; ++ ++/* now some defines to make these easier to use. */ ++#define spk_shut_up speakup_console[vc->vc_num]->shut_up ++#define spk_killed (speakup_console[vc->vc_num]->shut_up & 0x40) ++#define spk_x speakup_console[vc->vc_num]->reading_x ++#define spk_cx speakup_console[vc->vc_num]->cursor_x ++#define spk_y speakup_console[vc->vc_num]->reading_y ++#define spk_cy speakup_console[vc->vc_num]->cursor_y ++#define spk_pos (speakup_console[vc->vc_num]->reading_pos) ++#define spk_cp speakup_console[vc->vc_num]->cursor_pos ++#define goto_pos (speakup_console[vc->vc_num]->go_pos) ++#define goto_x (speakup_console[vc->vc_num]->go_x) ++#define win_top (speakup_console[vc->vc_num]->w_top) ++#define win_bottom (speakup_console[vc->vc_num]->w_bottom) ++#define win_left (speakup_console[vc->vc_num]->w_left) ++#define win_right (speakup_console[vc->vc_num]->w_right) ++#define win_start (speakup_console[vc->vc_num]->w_start) ++#define win_enabled (speakup_console[vc->vc_num]->w_enabled) ++#define spk_attr speakup_console[vc->vc_num]->reading_attr ++#define spk_old_attr speakup_console[vc->vc_num]->old_attr ++#define spk_parked speakup_console[vc->vc_num]->parked ++ ++struct st_var_header { ++ char *name; ++ enum var_id_t var_id; ++ enum var_type_t var_type; ++ void *p_val; /* ptr to programs variable to store value */ ++ void *data; /* ptr to the vars data */ ++}; ++ ++struct num_var_t { ++ char *synth_fmt; ++ int default_val; ++ int low; ++ int high; ++ short offset, multiplier; /* for fiddling rates etc. */ ++ char *out_str; /* if synth needs char representation of number */ ++ int value; /* current value */ ++}; ++ ++struct punc_var_t { ++ enum var_id_t var_id; ++ short value; ++}; ++ ++struct string_var_t { ++ char *default_val; ++}; ++ ++struct var_t { ++ enum var_id_t var_id; ++ union { ++ struct num_var_t n; ++ struct string_var_t s; ++ } u; ++}; ++ ++struct st_bits_data { /* punc, repeats, word delim bits */ ++ char *name; ++ char *value; ++ short mask; ++}; ++ ++struct synth_indexing { ++ char *command; ++ unsigned char lowindex; ++ unsigned char highindex; ++ unsigned char currindex; ++}; ++ ++struct spk_synth { ++ const char *name; ++ const char *version; ++ const char *long_name; ++ const char *init; ++ char procspeech; ++ char clear; ++ int delay; ++ int trigger; ++ int jiffies; ++ int full; ++ int ser; ++ short flags; ++ short startup; ++ const int checkval; /* for validating a proper synth module */ ++ struct var_t *vars; ++ int (*probe)(struct spk_synth *synth); ++ void (*release)(void); ++ const char *(*synth_immediate)(struct spk_synth *synth, const char *buff); ++ void (*catch_up)(struct spk_synth *synth); ++ void (*flush)(struct spk_synth *synth); ++ int (*is_alive)(struct spk_synth *synth); ++ int (*synth_adjust)(struct st_var_header *var); ++ void (*read_buff_add)(u_char); ++ unsigned char (*get_index)(void); ++ struct synth_indexing indexing; ++ int alive; ++ struct attribute_group attributes; ++}; ++ ++struct speakup_info_t { ++ spinlock_t spinlock; ++ int port_tts; ++ int flushing; ++}; ++ ++#endif +--- a/drivers/staging/speakup/synth.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/synth.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,458 @@ ++#include ++#include /* for isdigit() and friends */ ++#include ++#include /* for verify_area */ ++#include /* for -EBUSY */ ++#include /* for check_region, request_region */ ++#include ++#include /* for loops_per_sec */ ++#include ++#include ++#include /* for copy_from_user */ ++#include ++#include ++#include ++ ++#include "spk_priv.h" ++#include "speakup.h" ++#include "serialio.h" ++ ++#define MAXSYNTHS 16 /* Max number of synths in array. */ ++static struct spk_synth *synths[MAXSYNTHS]; ++struct spk_synth *synth = NULL; ++char pitch_buff[32] = ""; ++static int module_status; ++int quiet_boot; ++ ++struct speakup_info_t speakup_info = { ++ .spinlock = SPIN_LOCK_UNLOCKED, ++ .flushing = 0, ++}; ++EXPORT_SYMBOL_GPL(speakup_info); ++ ++static int do_synth_init(struct spk_synth *in_synth); ++ ++int serial_synth_probe(struct spk_synth *synth) ++{ ++ struct serial_state *ser; ++ int failed = 0; ++ ++ if ((synth->ser >= SPK_LO_TTY) && (synth->ser <= SPK_HI_TTY)) { ++ ser = spk_serial_init(synth->ser); ++ if (ser == NULL) { ++ failed = -1; ++ } else { ++ outb_p(0, ser->port); ++ mdelay(1); ++ outb_p('\r', ser->port); ++ } ++ } else { ++ failed = -1; ++ pr_warn("ttyS%i is an invalid port\n", synth->ser); ++ } ++ if (failed) { ++ pr_info("%s: not found\n", synth->long_name); ++ return -ENODEV; ++ } ++ pr_info("%s: ttyS%i, Driver Version %s\n", ++ synth->long_name, synth->ser, synth->version); ++ synth->alive = 1; ++ return 0; ++} ++EXPORT_SYMBOL_GPL(serial_synth_probe); ++ ++/* Main loop of the progression thread: keep eating from the buffer ++ * and push to the serial port, waiting as needed ++ * ++ * For devices that have a "full" notification mecanism, the driver can ++ * adapt the loop the way they prefer. ++ */ ++void spk_do_catch_up(struct spk_synth *synth) ++{ ++ u_char ch; ++ unsigned long flags; ++ unsigned long jiff_max; ++ struct var_t *delay_time; ++ struct var_t *full_time; ++ struct var_t *jiffy_delta; ++ int jiffy_delta_val; ++ int delay_time_val; ++ int full_time_val; ++ ++ jiffy_delta = get_var(JIFFY); ++ full_time = get_var(FULL); ++ delay_time = get_var(DELAY); ++ ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ spk_unlock(flags); ++ ++ jiff_max = jiffies + jiffy_delta_val; ++ while (!kthread_should_stop()) { ++ spk_lock(flags); ++ if (speakup_info.flushing) { ++ speakup_info.flushing = 0; ++ spk_unlock(flags); ++ synth->flush(synth); ++ continue; ++ } ++ if (synth_buffer_empty()) { ++ spk_unlock(flags); ++ break; ++ } ++ ch = synth_buffer_peek(); ++ set_current_state(TASK_INTERRUPTIBLE); ++ full_time_val = full_time->u.n.value; ++ spk_unlock(flags); ++ if (ch == '\n') ++ ch = synth->procspeech; ++ if (!spk_serial_out(ch)) { ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ continue; ++ } ++ if ((jiffies >= jiff_max) && (ch == SPACE)) { ++ spk_lock(flags); ++ jiffy_delta_val = jiffy_delta->u.n.value; ++ delay_time_val = delay_time->u.n.value; ++ full_time_val = full_time->u.n.value; ++ spk_unlock(flags); ++ if (spk_serial_out(synth->procspeech)) ++ schedule_timeout(msecs_to_jiffies(delay_time_val)); ++ else ++ schedule_timeout(msecs_to_jiffies(full_time_val)); ++ jiff_max = jiffies + jiffy_delta_val; ++ } ++ set_current_state(TASK_RUNNING); ++ spk_lock(flags); ++ synth_buffer_getc(); ++ spk_unlock(flags); ++ } ++ spk_serial_out(synth->procspeech); ++} ++EXPORT_SYMBOL_GPL(spk_do_catch_up); ++ ++const char *spk_synth_immediate(struct spk_synth *synth, const char *buff) ++{ ++ u_char ch; ++ while ((ch = *buff)) { ++ if (ch == '\n') ++ ch = synth->procspeech; ++ if (wait_for_xmitr()) ++ outb(ch, speakup_info.port_tts); ++ else ++ return buff; ++ buff++; ++ } ++ return 0; ++} ++EXPORT_SYMBOL_GPL(spk_synth_immediate); ++ ++void spk_synth_flush(struct spk_synth *synth) ++{ ++ spk_serial_out(synth->clear); ++} ++EXPORT_SYMBOL_GPL(spk_synth_flush); ++ ++int spk_synth_is_alive_nop(struct spk_synth *synth) ++{ ++ synth->alive = 1; ++ return 1; ++} ++EXPORT_SYMBOL_GPL(spk_synth_is_alive_nop); ++ ++int spk_synth_is_alive_restart(struct spk_synth *synth) ++{ ++ if (synth->alive) ++ return 1; ++ if (!synth->alive && wait_for_xmitr() > 0) { ++ /* restart */ ++ synth->alive = 1; ++ synth_printf("%s", synth->init); ++ return 2; /* reenabled */ ++ } ++ pr_warn("%s: can't restart synth\n", synth->long_name); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(spk_synth_is_alive_restart); ++ ++static void thread_wake_up(u_long data) ++{ ++ wake_up_interruptible_all(&speakup_event); ++} ++ ++static DEFINE_TIMER(thread_timer, thread_wake_up, 0, 0); ++ ++void synth_start(void) ++{ ++ struct var_t *trigger_time; ++ ++ if (!synth->alive) { ++ synth_buffer_clear(); ++ return; ++ } ++ trigger_time = get_var(TRIGGER); ++ if (!timer_pending(&thread_timer)) ++ mod_timer(&thread_timer, jiffies + msecs_to_jiffies(trigger_time->u.n.value)); ++} ++ ++void do_flush(void) ++{ ++ speakup_info.flushing = 1; ++ synth_buffer_clear(); ++ if (synth->alive) { ++ if (pitch_shift) { ++ synth_printf("%s", pitch_buff); ++ pitch_shift = 0; ++ } ++ } ++ wake_up_interruptible_all(&speakup_event); ++ wake_up_process(speakup_task); ++} ++ ++void synth_write(const char *buf, size_t count) ++{ ++ while (count--) ++ synth_buffer_add(*buf++); ++ synth_start(); ++} ++ ++void synth_printf(const char *fmt, ...) ++{ ++ va_list args; ++ unsigned char buf[160], *p; ++ int r; ++ ++ va_start(args, fmt); ++ r = vsnprintf(buf, sizeof(buf), fmt, args); ++ va_end(args); ++ if (r > sizeof(buf) - 1) ++ r = sizeof(buf) - 1; ++ ++ p = buf; ++ while (r--) ++ synth_buffer_add(*p++); ++ synth_start(); ++} ++EXPORT_SYMBOL_GPL(synth_printf); ++ ++static int index_count = 0; ++static int sentence_count = 0; ++ ++void reset_index_count(int sc) ++{ ++ static int first = 1; ++ if (first) ++ first = 0; ++ else ++ synth->get_index(); ++ index_count = 0; ++ sentence_count = sc; ++} ++ ++int synth_supports_indexing(void) ++{ ++ if (synth->get_index != NULL) ++ return 1; ++ return 0; ++} ++ ++void synth_insert_next_index(int sent_num) ++{ ++ int out; ++ if (synth->alive) { ++ if (sent_num == 0) { ++ synth->indexing.currindex++; ++ index_count++; ++ if (synth->indexing.currindex > ++ synth->indexing.highindex) ++ synth->indexing.currindex = ++ synth->indexing.lowindex; ++ } ++ ++ out = synth->indexing.currindex * 10 + sent_num; ++ synth_printf(synth->indexing.command, out, out); ++ } ++} ++ ++void get_index_count(int *linecount, int *sentcount) ++{ ++ int ind = synth->get_index(); ++ if (ind) { ++ sentence_count = ind % 10; ++ ++ if ((ind / 10) <= synth->indexing.currindex) ++ index_count = synth->indexing.currindex-(ind/10); ++ else ++ index_count = synth->indexing.currindex-synth->indexing.lowindex ++ + synth->indexing.highindex-(ind/10)+1; ++ ++ } ++ *sentcount = sentence_count; ++ *linecount = index_count; ++} ++ ++static struct resource synth_res; ++ ++int synth_request_region(unsigned long start, unsigned long n) ++{ ++ struct resource *parent = &ioport_resource; ++ memset(&synth_res, 0, sizeof(synth_res)); ++ synth_res.name = synth->name; ++ synth_res.start = start; ++ synth_res.end = start + n - 1; ++ synth_res.flags = IORESOURCE_BUSY; ++ return request_resource(parent, &synth_res); ++} ++EXPORT_SYMBOL_GPL(synth_request_region); ++ ++int synth_release_region(unsigned long start, unsigned long n) ++{ ++ return release_resource(&synth_res); ++} ++EXPORT_SYMBOL_GPL(synth_release_region); ++ ++struct var_t synth_time_vars[] = { ++ { DELAY, .u.n = {NULL, 100, 100, 2000, 0, 0, NULL }}, ++ { TRIGGER, .u.n = {NULL, 20, 10, 2000, 0, 0, NULL }}, ++ { JIFFY, .u.n = {NULL, 50, 20, 200, 0, 0, NULL }}, ++ { FULL, .u.n = {NULL, 400, 200, 60000, 0, 0, NULL }}, ++ V_LAST_VAR ++}; ++ ++/* called by: speakup_init() */ ++int synth_init(char *synth_name) ++{ ++ int i; ++ int ret = 0; ++ struct spk_synth *synth = NULL; ++ ++ if (synth_name == NULL) ++ return 0; ++ ++ if (strcmp(synth_name, "none") == 0) { ++ mutex_lock(&spk_mutex); ++ synth_release(); ++ mutex_unlock(&spk_mutex); ++ return 0; ++ } ++ ++ mutex_lock(&spk_mutex); ++ /* First, check if we already have it loaded. */ ++ for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) ++ if (strcmp(synths[i]->name, synth_name) == 0) ++ synth = synths[i]; ++ ++ /* If we got one, initialize it now. */ ++ if (synth) ++ ret = do_synth_init(synth); ++ else ++ ret = -ENODEV; ++ mutex_unlock(&spk_mutex); ++ ++ return ret; ++} ++ ++/* called by: synth_add() */ ++static int do_synth_init(struct spk_synth *in_synth) ++{ ++ struct var_t *var; ++ ++ synth_release(); ++ if (in_synth->checkval != SYNTH_CHECK) ++ return -EINVAL; ++ synth = in_synth; ++ synth->alive = 0; ++ pr_warn("synth probe\n"); ++ if (synth->probe(synth) < 0) { ++ pr_warn("%s: device probe failed\n", in_synth->name); ++ synth = NULL; ++ return -ENODEV; ++ } ++ synth_time_vars[0].u.n.value = ++ synth_time_vars[0].u.n.default_val = synth->delay; ++ synth_time_vars[1].u.n.value = ++ synth_time_vars[1].u.n.default_val = synth->trigger; ++ synth_time_vars[2].u.n.value = ++ synth_time_vars[2].u.n.default_val = synth->jiffies; ++ synth_time_vars[3].u.n.value = ++ synth_time_vars[3].u.n.default_val = synth->full; ++ synth_printf("%s", synth->init); ++ for (var = synth->vars; (var->var_id >= 0) && (var->var_id < MAXVARS); var++) ++ speakup_register_var(var); ++ if (!quiet_boot) ++ synth_printf("%s found\n", synth->long_name); ++ if (synth->attributes.name ++ && sysfs_create_group(speakup_kobj, &(synth->attributes)) < 0) ++ return -ENOMEM; ++ synth_flags = synth->flags; ++ wake_up_interruptible_all(&speakup_event); ++ if (speakup_task) ++ wake_up_process(speakup_task); ++ return 0; ++} ++ ++void synth_release(void) ++{ ++ struct var_t *var; ++ unsigned long flags; ++ ++ if (synth == NULL) ++ return; ++ spk_lock(flags); ++ pr_info("releasing synth %s\n", synth->name); ++ synth->alive = 0; ++ del_timer(&thread_timer); ++ spk_unlock(flags); ++ if (synth->attributes.name) ++ sysfs_remove_group(speakup_kobj, &(synth->attributes)); ++ for (var = synth->vars; var->var_id != MAXVARS; var++) ++ speakup_unregister_var(var->var_id); ++ stop_serial_interrupt(); ++ synth->release(); ++ synth = NULL; ++} ++ ++/* called by: all_driver_init() */ ++int synth_add(struct spk_synth *in_synth) ++{ ++ int i; ++ int status = 0; ++ mutex_lock(&spk_mutex); ++ for (i = 0; synths[i] != NULL && i < MAXSYNTHS; i++) ++ /* synth_remove() is responsible for rotating the array down */ ++ if (in_synth == synths[i]) { ++ mutex_unlock(&spk_mutex); ++ return 0; ++ } ++ if (i == MAXSYNTHS) { ++ pr_warn("Error: attempting to add a synth past end of array\n"); ++ mutex_unlock(&spk_mutex); ++ return -1; ++ } ++ synths[i++] = in_synth; ++ synths[i] = NULL; ++ if (in_synth->startup) ++ status = do_synth_init(in_synth); ++ mutex_unlock(&spk_mutex); ++ return status; ++} ++EXPORT_SYMBOL_GPL(synth_add); ++ ++void synth_remove(struct spk_synth *in_synth) ++{ ++ int i; ++ mutex_lock(&spk_mutex); ++ if (synth == in_synth) ++ synth_release(); ++ for (i = 0; synths[i] != NULL; i++) { ++ if (in_synth == synths[i]) ++ break; ++ } ++ for ( ; synths[i] != NULL; i++) /* compress table */ ++ synths[i] = synths[i+1]; ++ module_status = 0; ++ mutex_unlock(&spk_mutex); ++} ++EXPORT_SYMBOL_GPL(synth_remove); ++ ++short punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM }; +--- a/drivers/staging/speakup/thread.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/thread.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,47 @@ ++#include ++#include ++ ++#include "spk_types.h" ++#include "speakup.h" ++#include "spk_priv.h" ++ ++DECLARE_WAIT_QUEUE_HEAD(speakup_event); ++EXPORT_SYMBOL_GPL(speakup_event); ++ ++int speakup_thread(void *data) ++{ ++ unsigned long flags; ++ int should_break; ++ ++ mutex_lock(&spk_mutex); ++ while (1) { ++ DEFINE_WAIT(wait); ++ while(1) { ++ spk_lock(flags); ++ prepare_to_wait(&speakup_event, &wait, TASK_INTERRUPTIBLE); ++ should_break = kthread_should_stop() || ++ (synth && synth->catch_up && synth->alive && ++ (speakup_info.flushing || ++ !synth_buffer_empty())); ++ spk_unlock(flags); ++ if (should_break) ++ break; ++ mutex_unlock(&spk_mutex); ++ schedule(); ++ mutex_lock(&spk_mutex); ++ } ++ finish_wait(&speakup_event, &wait); ++ if (kthread_should_stop()) ++ break; ++ ++ if (synth && synth->catch_up && synth->alive) { ++ /* It is up to the callee to take the lock, so that it ++ * can sleep whenever it likes */ ++ synth->catch_up(synth); ++ } ++ ++ speakup_start_ttys(); ++ } ++ mutex_unlock(&spk_mutex); ++ return 0; ++} +--- a/drivers/staging/speakup/varhandlers.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/drivers/staging/speakup/varhandlers.c 2009-08-13 01:21:12.000000000 +0100 +@@ -0,0 +1,395 @@ ++#include ++#include "spk_types.h" ++#include "spk_priv.h" ++#include "speakup.h" ++ ++static struct st_var_header var_headers[] = { ++ { "version", VERSION, VAR_PROC, NULL, NULL }, ++ { "synth_name", SYNTH, VAR_PROC, NULL, NULL }, ++ { "keymap", KEYMAP, VAR_PROC, NULL, NULL }, ++ { "silent", SILENT, VAR_PROC, NULL, NULL }, ++ { "punc_some", PUNC_SOME, VAR_PROC, NULL, NULL }, ++ { "punc_most", PUNC_MOST, VAR_PROC, NULL, NULL }, ++ { "punc_all", PUNC_ALL, VAR_PROC, NULL, NULL }, ++ { "delimiters", DELIM, VAR_PROC, NULL, NULL }, ++ { "repeats", REPEATS, VAR_PROC, NULL, NULL }, ++ { "ex_num", EXNUMBER, VAR_PROC, NULL, NULL }, ++ { "characters", CHARS, VAR_PROC, NULL, NULL }, ++ { "synth_direct", SYNTH_DIRECT, VAR_PROC, NULL, NULL }, ++ { "caps_start", CAPS_START, VAR_STRING, str_caps_start, NULL }, ++ { "caps_stop", CAPS_STOP, VAR_STRING, str_caps_stop, NULL }, ++ { "delay_time", DELAY, VAR_TIME, NULL, NULL }, ++ { "trigger_time", TRIGGER, VAR_TIME, NULL, NULL }, ++ { "jiffy_delta", JIFFY, VAR_TIME, NULL, NULL }, ++ { "full_time", FULL, VAR_TIME, NULL, NULL }, ++ { "spell_delay", SPELL_DELAY, VAR_NUM, &spell_delay, NULL }, ++ { "bleeps", BLEEPS, VAR_NUM, &bleeps, NULL }, ++ { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, &attrib_bleep, NULL }, ++ { "bleep_time", BLEEP_TIME, VAR_TIME, &bleep_time, NULL }, ++ { "cursor_time", CURSOR_TIME, VAR_TIME, NULL, NULL }, ++ { "punc_level", PUNC_LEVEL, VAR_NUM, &punc_level, NULL }, ++ { "reading_punc", READING_PUNC, VAR_NUM, &reading_punc, NULL }, ++ { "say_control", SAY_CONTROL, VAR_NUM, &say_ctrl, NULL }, ++ { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, &say_word_ctl, NULL }, ++ { "no_interrupt", NO_INTERRUPT, VAR_NUM, &no_intr, NULL }, ++ { "key_echo", KEY_ECHO, VAR_NUM, &key_echo, NULL }, ++ { "bell_pos", BELL_POS, VAR_NUM, &bell_pos, NULL }, ++ { "rate", RATE, VAR_NUM, NULL, NULL }, ++ { "pitch", PITCH, VAR_NUM, NULL, NULL }, ++ { "vol", VOL, VAR_NUM, NULL, NULL }, ++ { "tone", TONE, VAR_NUM, NULL, NULL }, ++ { "punct", PUNCT, VAR_NUM, NULL, NULL }, ++ { "voice", VOICE, VAR_NUM, NULL, NULL }, ++ { "freq", FREQUENCY, VAR_NUM, NULL, NULL }, ++ { "lang", LANG, VAR_NUM, NULL, NULL }, ++ { "chartab", CHARTAB, VAR_PROC, NULL, NULL }, ++ { "direct", DIRECT, VAR_NUM, NULL, NULL }, ++}; ++ ++static struct st_var_header *var_ptrs[MAXVARS] = { 0, 0, 0 }; ++ ++static struct punc_var_t punc_vars[] = { ++ { PUNC_SOME, 1 }, ++ { PUNC_MOST, 2 }, ++ { PUNC_ALL, 3 }, ++ { DELIM, 4 }, ++ { REPEATS, 5 }, ++ { EXNUMBER, 6 }, ++ { -1, -1 }, ++}; ++ ++int chartab_get_value(char *keyword) ++{ ++ int value = 0; ++ ++ if (!strcmp(keyword, "ALPHA")) ++ value = ALPHA; ++ else if (!strcmp(keyword, "B_CTL")) ++ value = B_CTL; ++ else if (!strcmp(keyword, "WDLM")) ++ value = WDLM; ++ else if (!strcmp(keyword, "A_PUNC")) ++ value = A_PUNC; ++ else if (!strcmp(keyword, "PUNC")) ++ value = PUNC; ++ else if (!strcmp(keyword, "NUM")) ++ value = NUM; ++ else if (!strcmp(keyword, "A_CAP")) ++ value = A_CAP; ++ else if (!strcmp(keyword, "B_CAPSYM")) ++ value = B_CAPSYM; ++ else if (!strcmp(keyword, "B_SYM")) ++ value = B_SYM; ++ return value; ++} ++ ++void speakup_register_var(struct var_t *var) ++{ ++ static char nothing[2] = "\0"; ++ int i; ++ struct st_var_header *p_header; ++ ++ BUG_ON(!var || var->var_id < 0 || var->var_id >= MAXVARS); ++ if (var_ptrs[0] == NULL) { ++ for (i = 0; i < MAXVARS; i++) { ++ p_header = &var_headers[i]; ++ var_ptrs[p_header->var_id] = p_header; ++ p_header->data = NULL; ++ } ++ } ++ p_header = var_ptrs[var->var_id]; ++ if (p_header->data != NULL) ++ return; ++ p_header->data = var; ++ switch (p_header->var_type) { ++ case VAR_STRING: ++ set_string_var(nothing, p_header, 0); ++ break; ++ case VAR_NUM: ++ case VAR_TIME: ++ set_num_var(0, p_header, E_DEFAULT); ++ break; ++ default: ++ break; ++ } ++ return; ++} ++ ++void speakup_unregister_var(enum var_id_t var_id) ++{ ++ struct st_var_header *p_header; ++ BUG_ON(var_id < 0 || var_id >= MAXVARS); ++ p_header = var_ptrs[var_id]; ++ p_header->data = NULL; ++} ++ ++struct st_var_header *get_var_header(enum var_id_t var_id) ++{ ++ struct st_var_header *p_header; ++ if (var_id < 0 || var_id >= MAXVARS) ++ return NULL; ++ p_header = var_ptrs[var_id]; ++ if (p_header->data == NULL) ++ return NULL; ++ return p_header; ++} ++ ++struct st_var_header *var_header_by_name(const char *name) ++{ ++ int i; ++ struct st_var_header *where = NULL; ++ ++ if (name != NULL) { ++ i = 0; ++ while ((i < MAXVARS) && (where == NULL)) { ++ if (strcmp(name, var_ptrs[i]->name) == 0) ++ where = var_ptrs[i]; ++ else ++ i++; ++ } ++ } ++ return where; ++} ++ ++struct var_t *get_var(enum var_id_t var_id) ++{ ++ BUG_ON(var_id < 0 || var_id >= MAXVARS); ++ BUG_ON(! var_ptrs[var_id]); ++ return (var_ptrs[var_id]->data); ++} ++EXPORT_SYMBOL_GPL(get_var); ++ ++struct punc_var_t *get_punc_var(enum var_id_t var_id) ++{ ++ struct punc_var_t *rv = NULL; ++ struct punc_var_t *where; ++ ++ where = punc_vars; ++ while ((where->var_id != -1) && (rv == NULL)) { ++ if (where->var_id == var_id) ++ rv = where; ++ else ++ where++; ++ } ++ return rv; ++} ++ ++/* handlers for setting vars */ ++int set_num_var(int input, struct st_var_header *var, int how) ++{ ++ int val; ++ short ret = 0; ++ int *p_val = var->p_val; ++ int l; ++ char buf[32]; ++ char *cp; ++ struct var_t *var_data = var->data; ++ if (var_data == NULL) ++ return E_UNDEF; ++ if (how == E_DEFAULT) { ++ val = var_data->u.n.default_val; ++ ret = SET_DEFAULT; ++ } else { ++ if (how == E_SET) ++ val = input; ++ else ++ val = var_data->u.n.value; ++ if (how == E_INC) ++ val += input; ++ else if (how == E_DEC) ++ val -= input; ++ if (val < var_data->u.n.low || val > var_data->u.n.high) ++ return E_RANGE; ++ } ++ var_data->u.n.value = val; ++ if (var->var_type == VAR_TIME && p_val != NULL) { ++ *p_val = msecs_to_jiffies(val); ++ return ret; ++ } ++ if (p_val != NULL) ++ *p_val = val; ++ if (var->var_id == PUNC_LEVEL) { ++ punc_mask = punc_masks[val]; ++ return ret; ++ } ++ if (var_data->u.n.multiplier != 0) ++ val *= var_data->u.n.multiplier; ++ val += var_data->u.n.offset; ++ if (var->var_id < FIRST_SYNTH_VAR || synth == NULL) ++ return ret; ++ if (synth->synth_adjust != NULL) { ++ int status = synth->synth_adjust(var); ++ return (status != 0) ? status : ret; ++ } ++ if (!var_data->u.n.synth_fmt) ++ return ret; ++ if (var->var_id == PITCH) ++ cp = pitch_buff; ++ else ++ cp = buf; ++ if (!var_data->u.n.out_str) ++ l = sprintf(cp, var_data->u.n.synth_fmt, (int)val); ++ else ++ l = sprintf(cp, var_data->u.n.synth_fmt, var_data->u.n.out_str[val]); ++ synth_printf("%s", cp); ++ return ret; ++} ++ ++int set_string_var(const char *page, struct st_var_header *var, int len) ++{ ++ int ret = 0; ++ struct var_t *var_data = var->data; ++ if (var_data == NULL) ++ return E_UNDEF; ++ if (len > MAXVARLEN) ++ return -E_TOOLONG; ++ if (!len) { ++ if (!var_data->u.s.default_val) ++ return 0; ++ ret = SET_DEFAULT; ++ if (!var->p_val) ++ var->p_val = var_data->u.s.default_val; ++ if (var->p_val != var_data->u.s.default_val) ++ strcpy((char *)var->p_val, var_data->u.s.default_val); ++ } else if (var->p_val) ++ strcpy((char *)var->p_val, page); ++ else ++ return -E_TOOLONG; ++ return ret; ++} ++ ++/* set_mask_bits sets or clears the punc/delim/repeat bits, ++ * if input is null uses the defaults. ++ * values for how: 0 clears bits of chars supplied, ++ * 1 clears allk, 2 sets bits for chars */ ++int set_mask_bits(const char *input, const int which, const int how) ++{ ++ u_char *cp; ++ short mask = punc_info[which].mask; ++ if (how&1) { ++ for (cp = (u_char *)punc_info[3].value; *cp; cp++) ++ spk_chartab[*cp] &= ~mask; ++ } ++ cp = (u_char *)input; ++ if (cp == 0) ++ cp = punc_info[which].value; ++ else { ++ for ( ; *cp; cp++) { ++ if (*cp < SPACE) ++ break; ++ if (mask < PUNC) { ++ if (!(spk_chartab[*cp]&PUNC)) ++ break; ++ } else if (spk_chartab[*cp]&B_NUM) ++ break; ++ } ++ if (*cp) ++ return -EINVAL; ++ cp = (u_char *)input; ++ } ++ if (how&2) { ++ for ( ; *cp; cp++) ++ if (*cp > SPACE) ++ spk_chartab[*cp] |= mask; ++ } else { ++ for ( ; *cp; cp++) ++ if (*cp > SPACE) ++ spk_chartab[*cp] &= ~mask; ++ } ++ return 0; ++} ++ ++char *strlwr(char *s) ++{ ++ char *p; ++ if (s == NULL) ++ return NULL; ++ ++ for (p = s; *p; p++) ++ *p = tolower(*p); ++ return s; ++} ++ ++char *speakup_s2i(char *start, int *dest) ++{ ++ int val; ++ char ch = *start; ++ if (ch == '-' || ch == '+') ++ start++; ++ if (*start < '0' || *start > '9') ++ return start; ++ val = (*start) - '0'; ++ start++; ++ while (*start >= '0' && *start <= '9') { ++ val *= 10; ++ val += (*start) - '0'; ++ start++; ++ } ++ if (ch == '-') ++ *dest = -val; ++ else ++ *dest = val; ++ return start; ++} ++ ++char *s2uchar(char *start, char *dest) ++{ ++ int val = 0; ++ while (*start && *start <= SPACE) ++ start++; ++ while (*start >= '0' && *start <= '9') { ++ val *= 10; ++ val += (*start) - '0'; ++ start++; ++ } ++ if (*start == ',') ++ start++; ++ *dest = (u_char)val; ++ return start; ++} ++ ++char *xlate(char *s) ++{ ++ static const char finds[] = "nrtvafe"; ++ static const char subs[] = "\n\r\t\013\001\014\033"; ++ static const char hx[] = "0123456789abcdefABCDEF"; ++ char *p = s, *p1, *p2, c; ++ int num; ++ while ((p = strchr(p, '\\'))) { ++ p1 = p+1; ++ p2 = strchr(finds, *p1); ++ if (p2) { ++ *p++ = subs[p2-finds]; ++ p1++; ++ } else if (*p1 >= '0' && *p1 <= '7') { ++ num = (*p1++)&7; ++ while (num < 256 && *p1 >= '0' && *p1 <= '7') { ++ num <<= 3; ++ num = (*p1++)&7; ++ } ++ *p++ = num; ++ } else if (*p1 == 'x' && ++ strchr(hx, p1[1]) && strchr(hx, p1[2])) { ++ p1++; ++ c = *p1++; ++ if (c > '9') ++ c = (c - '7') & 0x0f; ++ else ++ c -= '0'; ++ num = c << 4; ++ c = *p1++; ++ if (c > '9') ++ c = (c-'7')&0x0f; ++ else ++ c -= '0'; ++ num += c; ++ *p++ = num; ++ } else ++ *p++ = *p1++; ++ p2 = p; ++ while (*p1) ++ *p2++ = *p1++; ++ *p2 = '\0'; ++ } ++ return s; ++} diff --git a/debian/patches/features/all/speakup/speakup-kbuild.patch b/debian/patches/features/all/speakup/speakup-kbuild.patch new file mode 100644 index 000000000..604e7e476 --- /dev/null +++ b/debian/patches/features/all/speakup/speakup-kbuild.patch @@ -0,0 +1,28 @@ +From: Ben Hutchings +Subject: [PATCH] speakup: integrate into kbuild + +--- a/drivers/staging/Kconfig ++++ b/drivers/staging/Kconfig +@@ -126,6 +126,8 @@ + source "drivers/staging/pata_rdc/Kconfig" + + source "drivers/staging/udlfb/Kconfig" ++ ++source "drivers/staging/speakup/Kconfig" + + endif # !STAGING_EXCLUDE_BUILD + endif # STAGING +--- a/drivers/staging/Makefile ++++ b/drivers/staging/Makefile +@@ -45,3 +45,4 @@ + obj-$(CONFIG_USB_CPC) += cpc-usb/ + obj-$(CONFIG_RDC_17F3101X) += pata_rdc/ + obj-$(CONFIG_FB_UDL) += udlfb/ ++obj-$(CONFIG_SPEAKUP) += speakup/ +--- a/drivers/staging/speakup/Kbuild ++++ b/drivers/staging/speakup/Kbuild +@@ -1,4 +1,3 @@ +-include $M/allmodule.mk + obj-$(CONFIG_SPEAKUP_SYNTH_ACNTSA) += speakup_acntsa.o + obj-$(CONFIG_SPEAKUP_SYNTH_ACNTPC) += speakup_acntpc.o + obj-$(CONFIG_SPEAKUP_SYNTH_APOLLO) += speakup_apollo.o diff --git a/debian/patches/series/base b/debian/patches/series/base index 4cc80eb26..1521804a1 100644 --- a/debian/patches/series/base +++ b/debian/patches/series/base @@ -25,6 +25,11 @@ # mark as staging/crap + features/all/aufs2/mark-as-staging.patch +# content of src/ from speakup package; generated with: +# diff -ur --unidirectional-new-file nonexistent src | filterdiff --strip=1 --addoldprefix=a/drivers/staging/speakup/ --addnewprefix=b/drivers/staging/speakup/ ++ features/all/speakup/speakup-add.patch ++ features/all/speakup/speakup-kbuild.patch + + bugfix/sparc/drivers_net-broken.patch #+ bugfix/ia64/hardcode-arch-script-output.patch + bugfix/mips/disable-advansys.patch