[kernel] r14380 - in dists/trunk/linux-2.6/debian: . config/kernelarch-x86 patches/features/all/speakup patches/series

Ben Hutchings benh at alioth.debian.org
Tue Oct 13 05:17:46 UTC 2009


Author: benh
Date: Tue Oct 13 05:17:42 2009
New Revision: 14380

Log:
Include speakup modules under staging

Added:
   dists/trunk/linux-2.6/debian/patches/features/all/speakup/
   dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-add.patch
   dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-kbuild.patch
Modified:
   dists/trunk/linux-2.6/debian/changelog
   dists/trunk/linux-2.6/debian/config/kernelarch-x86/config
   dists/trunk/linux-2.6/debian/patches/series/base

Modified: dists/trunk/linux-2.6/debian/changelog
==============================================================================
--- dists/trunk/linux-2.6/debian/changelog	Tue Oct 13 04:06:23 2009	(r14379)
+++ dists/trunk/linux-2.6/debian/changelog	Tue Oct 13 05:17:42 2009	(r14380)
@@ -2,6 +2,7 @@
 
   [ Ben Hutchings ]
   * Include aufs2, marked as staging (Closes: #541828)
+  * Include speakup modules under staging
 
  -- Ben Hutchings <ben at decadent.org.uk>  Tue, 13 Oct 2009 02:18:40 +0100
 

Modified: dists/trunk/linux-2.6/debian/config/kernelarch-x86/config
==============================================================================
--- dists/trunk/linux-2.6/debian/config/kernelarch-x86/config	Tue Oct 13 04:06:23 2009	(r14379)
+++ dists/trunk/linux-2.6/debian/config/kernelarch-x86/config	Tue Oct 13 05:17:42 2009	(r14380)
@@ -390,6 +390,25 @@
 # 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
 ##
 # CONFIG_STLC45XX is not set

Added: dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-add.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-add.patch	Tue Oct 13 05:17:42 2009	(r14380)
@@ -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 <linux/console.h>
++#include <linux/smp_lock.h>
++#include <linux/interrupt.h> /* for in_atomic */
++#include <linux/types.h>
++#include <linux/wait.h>
++
++#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 <linux/errno.h>
++#include <linux/miscdevice.h>	/* for misc_register, and SYNTH_MINOR */
++#include <linux/types.h>
++#include <linux/uaccess.h>
++
++#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 <linux/ctype.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#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 <linux/keyboard.h>
++#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 <greg at kroah.com>
++ * Copyright (C) 2007 Novell Inc.
++ *
++ * Released under the GPL version 2 only.
++ *
++ */
++#include <linux/kernel.h>
++#include <linux/kobject.h>
++#include <linux/string.h>
++#include <linux/sysfs.h>
++#include <linux/ctype.h>
++
++#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 <linux/kernel.h>
++#include <linux/version.h>
++#include <linux/vt.h>
++#include <linux/tty.h>
++#include <linux/mm.h> /* __get_free_page() and friends */
++#include <linux/vt_kern.h>
++#include <linux/ctype.h>
++#include <linux/selection.h>
++#include <linux/unistd.h>
++#include <linux/jiffies.h>
++#include <linux/kthread.h>
++#include <linux/keyboard.h>	/* for KT_SHIFT */
++#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
++#include <linux/input.h>
++#include <linux/kmod.h>
++
++#include <linux/bootmem.h>	/* for alloc_bootmem */
++
++/* speakup_*_selection */
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/types.h>
++#include <linux/consolemap.h>
++
++#include <linux/spinlock.h>
++#include <linux/notifier.h>
++
++#include <linux/uaccess.h> /* copy_from|to|user() and others */
++
++#include "spk_priv.h"
++#include "speakup.h"
++
++#define MAX_DELAY msecs_to_jiffies(500)
++#define MINECHOCHAR SPACE
++
++MODULE_AUTHOR("Kirk Reiser <kirk at braille.uwo.ca>");
++MODULE_AUTHOR("Daniel Drake <dsd at gentoo.org>");
++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 <linux/consolemap.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/selection.h>
++
++#include "speakup.h"
++
++/* ------ cut and paste ----- */
++/* Don't take this from <ctype.h>: 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 <linux/interrupt.h>
++#include <linux/ioport.h>
++
++#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 <linux/serial.h>	/* for rs_table, serial constants &
++				   serial_uart_config */
++#include <linux/serial_reg.h>	/* for more serial constants */
++#include <linux/serialP.h>	/* for struct serial_state */
++#ifndef __sparc__
++#include <asm/serial.h>
++#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 <kirk at braille.uwo.ca>
++ * this version considerably modified by David Borowski, david575 at 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 <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++
++#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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++
++#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 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++ * this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++
++#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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++ * this version considerably modified by David Borowski, david575 at 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 <linux/unistd.h>
++#include <linux/proc_fs.h>
++#include <linux/jiffies.h>
++#include <linux/spinlock.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++#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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++
++#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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++ * this version considerably modified by David Borowski, david575 at rogers.com
++ * eventually modified by Samuel Thibault <samuel.thibault at ens-lyon.org>
++ *
++ * 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 <samuel.thibault at ens-lyon.org>");
++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 <linux/version.h>
++
++#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 <linux/jiffies.h>
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++#include <linux/serial_reg.h>
++
++#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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++ *
++ * 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 <linux/unistd.h>
++#include <linux/miscdevice.h> /* for misc_register, and SYNTH_MINOR */
++#include <linux/poll.h> /* 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <kirk at braille.uwo.ca>
++* this version considerably modified by David Borowski, david575 at 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 <kirk at braille.uwo.ca>");
++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 <linux/types.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/delay.h>
++#include <linux/wait.h>		/* for wait_queue */
++#include <linux/init.h> /* for __init */
++#include <linux/module.h>
++#include <linux/vt_kern.h>
++#include <linux/spinlock.h>
++#include <linux/mutex.h>
++#include <linux/io.h>		/* 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 <linux/types.h>
++#include <linux/ctype.h>	/* for isdigit() and friends */
++#include <linux/fs.h>
++#include <linux/mm.h>		/* for verify_area */
++#include <linux/errno.h>	/* for -EBUSY */
++#include <linux/ioport.h>	/* for check_region, request_region */
++#include <linux/interrupt.h>
++#include <linux/delay.h>	/* for loops_per_sec */
++#include <linux/kmod.h>
++#include <linux/jiffies.h>
++#include <linux/uaccess.h> /* for copy_from_user */
++#include <linux/sched.h>
++#include <linux/timer.h>
++#include <linux/kthread.h>
++
++#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 <linux/kthread.h>
++#include <linux/wait.h>
++
++#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 <linux/ctype.h>
++#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;
++}

Added: dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-kbuild.patch
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/linux-2.6/debian/patches/features/all/speakup/speakup-kbuild.patch	Tue Oct 13 05:17:42 2009	(r14380)
@@ -0,0 +1,28 @@
+From: Ben Hutchings <ben at decadent.org.uk>
+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

Modified: dists/trunk/linux-2.6/debian/patches/series/base
==============================================================================
--- dists/trunk/linux-2.6/debian/patches/series/base	Tue Oct 13 04:06:23 2009	(r14379)
+++ dists/trunk/linux-2.6/debian/patches/series/base	Tue Oct 13 05:17:42 2009	(r14380)
@@ -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



More information about the Kernel-svn-changes mailing list