Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 sparc64/Kconfig                          |    0 
 MAINTAINERS                              |    7 
 arch/arm/Kconfig                         |    1 
 arch/mips/Kconfig                        |    2 
 drivers/Kconfig                          |    2 
 drivers/Makefile                         |    4 
 drivers/char/Makefile                    |    1 
 drivers/char/consolemap.c                |    1 
 drivers/char/keyboard.c                  |   44 
 drivers/char/speakup/Kconfig             |  210 ++
 drivers/char/speakup/Makefile            |   36 
 drivers/char/speakup/cvsversion.h        |    1 
 drivers/char/speakup/dtload.c            |  554 +++++++
 drivers/char/speakup/dtload.h            |   57 
 drivers/char/speakup/dtpc_reg.h          |  132 +
 drivers/char/speakup/genmap.c            |  204 ++
 drivers/char/speakup/keyinfo.h           |  119 +
 drivers/char/speakup/makemapdata.c       |  156 ++
 drivers/char/speakup/mapdata.h           |  238 +++
 drivers/char/speakup/mod_code.c          |   25 
 drivers/char/speakup/serialio.h          |   18 
 drivers/char/speakup/speakup.c           | 2281 +++++++++++++++++++++++++++++++
 drivers/char/speakup/speakup_acnt.h      |   16 
 drivers/char/speakup/speakup_acntpc.c    |  160 ++
 drivers/char/speakup/speakup_acntsa.c    |  184 ++
 drivers/char/speakup/speakup_apollo.c    |  195 ++
 drivers/char/speakup/speakup_audptr.c    |  201 ++
 drivers/char/speakup/speakup_bns.c       |  174 ++
 drivers/char/speakup/speakup_decext.c    |  205 ++
 drivers/char/speakup/speakup_decpc.c     |  242 +++
 drivers/char/speakup/speakup_dectlk.c    |  221 +++
 drivers/char/speakup/speakup_drvcommon.c |  879 +++++++++++
 drivers/char/speakup/speakup_dtlk.c      |  219 ++
 drivers/char/speakup/speakup_dtlk.h      |   54 
 drivers/char/speakup/speakup_keyhelp.c   |  294 +++
 drivers/char/speakup/speakup_keypc.c     |  189 ++
 drivers/char/speakup/speakup_ltlk.c      |  215 ++
 drivers/char/speakup/speakup_sftsyn.c    |  175 ++
 drivers/char/speakup/speakup_spkout.c    |  188 ++
 drivers/char/speakup/speakup_txprt.c     |  195 ++
 drivers/char/speakup/speakupconf         |   51 
 drivers/char/speakup/speakupmap.h        |   64 
 drivers/char/speakup/speakupmap.map      |   91 +
 drivers/char/speakup/spk_con_module.h    |   43 
 drivers/char/speakup/spk_priv.h          |  258 +++
 drivers/char/speakup/synthlist.h         |   54 
 drivers/char/vt.c                        |   16 
 include/linux/keyboard.h                 |    2 
 include/linux/speakup.h                  |   33 
 49 files changed, 8702 insertions(+), 9 deletions(-)

diff -puN arch/arm/Kconfig~gregkh-driver-speakup-core arch/arm/Kconfig
--- devel/arch/arm/Kconfig~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/arch/arm/Kconfig	2005-09-07 19:39:50.000000000 -0700
@@ -724,6 +724,7 @@ source "drivers/mfd/Kconfig"
 source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
+source "drivers/char/speakup/Kconfig"
 
 source "sound/Kconfig"
 
diff -puN arch/mips/Kconfig~gregkh-driver-speakup-core arch/mips/Kconfig
--- devel/arch/mips/Kconfig~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/arch/mips/Kconfig	2005-09-07 19:39:50.000000000 -0700
@@ -924,6 +924,8 @@ config SIBYTE_STANDALONE
 	depends on SIBYTE_SB1xxx_SOC && !SIBYTE_CFE
 	default y
 
+source "drivers/char/speakup/Kconfig"
+
 config SIBYTE_STANDALONE_RAM_SIZE
 	int "Memory size (in megabytes)"
 	depends on SIBYTE_STANDALONE
diff -puN arch/sparc64/Kconfig~gregkh-driver-speakup-core arch/sparc64/Kconfig
diff -puN drivers/char/consolemap.c~gregkh-driver-speakup-core drivers/char/consolemap.c
--- devel/drivers/char/consolemap.c~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/char/consolemap.c	2005-09-07 19:39:50.000000000 -0700
@@ -670,3 +670,4 @@ console_map_init(void)
 }
 
 EXPORT_SYMBOL(con_copy_unimap);
+EXPORT_SYMBOL(inverse_translate);
diff -puN drivers/char/keyboard.c~gregkh-driver-speakup-core drivers/char/keyboard.c
--- devel/drivers/char/keyboard.c~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/char/keyboard.c	2005-09-07 19:39:50.000000000 -0700
@@ -40,6 +40,13 @@
 #include <linux/sysrq.h>
 #include <linux/input.h>
 
+
+#include <linux/speakup.h>
+
+#ifdef CONFIG_SPEAKUP_MODULE
+spk_key_func addr_spk_key = NULL;
+#endif
+
 static void kbd_disconnect(struct input_handle *handle);
 extern void ctrl_alt_del(void);
 
@@ -64,6 +71,10 @@ extern void ctrl_alt_del(void);
 
 #define KBD_DEFLOCK 0
 
+/* Key types processed even in raw modes */
+
+#define TYPES_ALLOWED_IN_RAW_MODE ((1 << KT_SPEC) | (1 << KT_SHIFT) | (1 << KT_SPKUP))
+
 void compute_shiftstate(void);
 
 /*
@@ -79,7 +90,7 @@ void compute_shiftstate(void);
 typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value, 
 			    char up_flag, struct pt_regs *regs);
 static k_handler_fn K_HANDLERS;
-static k_handler_fn *k_handler[16] = { K_HANDLERS };
+k_handler_fn *k_handler[16] = { K_HANDLERS };
 
 #define FN_HANDLERS\
 	fn_null, 	fn_enter,	fn_show_ptregs,	fn_show_mem,\
@@ -100,15 +111,18 @@ static fn_handler_fn *fn_handler[] = { F
 const int max_vals[] = {
 	255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1,
 	NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1,
-	255, NR_LOCK - 1, 255
+	255, NR_LOCK - 1, 255, 255
 };
 
 const int NR_TYPES = ARRAY_SIZE(max_vals);
 
 struct kbd_struct kbd_table[MAX_NR_CONSOLES];
-static struct kbd_struct *kbd = kbd_table;
+struct kbd_struct *kbd = kbd_table;
 static struct kbd_struct kbd0;
 
+EXPORT_SYMBOL(kbd);
+EXPORT_SYMBOL(k_handler);
+
 int spawnpid, spawnsig;
 
 /*
@@ -256,12 +270,14 @@ void kd_mksound(unsigned int hz, unsigne
 				}
 			}
 		}
-		if (ticks)
-			mod_timer(&kd_mksound_timer, jiffies + ticks);
+                if (ticks)
+                        mod_timer(&kd_mksound_timer, jiffies + ticks);
 	} else
 		kd_nosound(0);
 }
 
+EXPORT_SYMBOL(kd_mksound);
+
 /*
  * Setting the keyboard rate.
  */
@@ -603,6 +619,7 @@ static void k_spec(struct vc_data *vc, u
 	if (up_flag)
 		return;
 	if (value >= ARRAY_SIZE(fn_handler))
+		if (up_flag || (value >= ARRAY_SIZE(fn_handler)))
 		return;
 	if ((kbd->kbdmode == VC_RAW || 
 	     kbd->kbdmode == VC_MEDIUMRAW) && 
@@ -1119,6 +1136,13 @@ static void kbd_keycode(unsigned int key
 	key_map = key_maps[shift_final];
 
 	if (!key_map) {
+#ifdef CONFIG_SPEAKUP
+		if (speakup_key(vc, shift_final, keycode, K(KT_SHIFT,0), !down, regs ))
+			return;
+#elif defined(CONFIG_SPEAKUP_MODULE)
+		if ( addr_spk_key && (*addr_spk_key)(vc, shift_final,
+			keycode, K(KT_SHIFT,0), !down, regs) ) return;
+#endif
 		compute_shiftstate();
 		kbd->slockstate = 0;
 		return;
@@ -1136,8 +1160,15 @@ static void kbd_keycode(unsigned int key
 	}
 
 	type -= 0xf0;
+#ifdef CONFIG_SPEAKUP
+	if (speakup_key(vc, shift_final, keycode, keysym, !down, regs ))
+		return;
+#elif defined(CONFIG_SPEAKUP_MODULE)
+	if ( addr_spk_key && (*addr_spk_key)(vc, shift_final,
+		keycode, keysym, !down, regs) ) return;
+#endif
 
-	if (raw_mode && type != KT_SPEC && type != KT_SHIFT)
+	if (raw_mode && type != KT_SPEC && type != KT_SHIFT )
 		return;
 
 	if (type == KT_LETTER) {
@@ -1148,7 +1179,6 @@ static void kbd_keycode(unsigned int key
 				keysym = key_map[keycode];
 		}
 	}
-
 	(*k_handler[type])(vc, keysym & 0xff, !down, regs);
 
 	if (type != KT_SLOCK)
diff -puN drivers/char/Makefile~gregkh-driver-speakup-core drivers/char/Makefile
--- devel/drivers/char/Makefile~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/char/Makefile	2005-09-07 19:39:50.000000000 -0700
@@ -83,6 +83,7 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio
 obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
 obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
 
+obj-$(CONFIG_SPEAKUP) += speakup/
 obj-$(CONFIG_WATCHDOG)	+= watchdog/
 obj-$(CONFIG_MWAVE) += mwave/
 obj-$(CONFIG_AGP) += agp/
diff -puN /dev/null drivers/char/speakup/cvsversion.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/cvsversion.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1 @@
+#define CVSVERSION " CVS: Wed Mar 2 20:22:02 EST 2005 "
diff -puN /dev/null drivers/char/speakup/dtload.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/dtload.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,554 @@
+/*
+ * This is the DECtalk PC firmware loader for the Linux kernel, version 1.0
+ *
+ * Original 386BSD source:
+ *      Copyright ( c ) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
+ *
+ * Adapted for Linux:
+ *      Copyright ( c ) 1997 Nicolas Pitre <nico@cam.org>
+ *
+ * Adapted for speakup:
+ *      Copyright ( c ) 2003 David Borowski <david575@golden.net>
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <sys/errno.h>
+#include <asm/io.h>
+#include "dtload.h"
+#include "dtpc_reg.h"
+
+#define dt_delay(x) usleep(x)
+int verbose = 0, intest = 0,infd = -1;
+int image_len, total_paras;
+int dt_stat, dma_state = 0, has_kernel = 0;
+struct dos_reloc fixups[512];
+char *read_buff = NULL;
+struct dos_exe_header header;
+u_short iobase = 0x350;
+
+static inline int dt_getstatus( )
+{
+  dt_stat =  inb_p( iobase )|(inb_p( iobase+1 )<<8);
+  return dt_stat;
+}
+
+static void dt_sendcmd( u_int cmd )
+{
+  outb_p( cmd & 0xFF, iobase );
+  outb_p( (cmd>>8) & 0xFF, iobase+1 );
+}
+
+static int dt_waitbit( int bit )
+{
+  int timeout = 100;
+  while ( --timeout > 0 ) {
+    if( (dt_getstatus( ) & bit ) == bit ) return 1;
+    usleep( 1000 );
+  }
+  return 0;
+}
+
+static int dt_sendcmd_wait( u_int cmd, int bit )
+{
+  int timeout = 1000;
+  outb_p( cmd & 0xFF, iobase );
+  outb_p( (cmd>>8) & 0xFF, iobase+1 );
+  while ( --timeout > 0 ) {
+    if( (dt_getstatus( ) & bit ) == bit ) return 1;
+    usleep( 1000 );
+  }
+  return 0;
+}
+
+static int dt_waitmode( int pattern )
+{
+  int timeout = 1000;
+  while ( --timeout > 0 ) {
+    if( dt_getstatus( ) == pattern ) return 1;
+    usleep( 1000 );
+  }
+  fprintf( stderr, "waitmode p=%x s = %x\n", pattern, dt_stat );
+  return 0;
+}
+
+static int dt_wait_dma( )
+{
+  int timeout = 1000, state = dma_state;
+  if( !has_kernel ){
+    dt_delay( 500 );
+    return( dt_waitbit( STAT_dma_ready ) );
+  }
+  if( ! dt_waitbit( STAT_dma_ready ) ) return 0;
+  while ( --timeout > 0 ) {
+    if( (dt_getstatus()&STAT_dma_state) == state ) return 1;
+    usleep( 1000 );
+  }
+  dma_state = dt_getstatus( ) & STAT_dma_state;
+  return 1;
+}
+
+dt_ctrl( u_int cmd )
+{
+  while ( ! dt_waitbit( STAT_cmd_ready ) ) dt_delay( 100 );
+  outb_p( 0, iobase+2 );
+  outb_p( 0, iobase+3 );
+  dt_getstatus( );
+  dt_sendcmd( CMD_control|cmd );
+  outb_p( 0, iobase+6 );
+  dt_delay( 100 );
+  dt_sendcmd( CMD_null );
+  while ( ! dt_waitbit( STAT_cmd_ready ) ) dt_delay( 100 );
+}
+
+int dt_flush( void )
+{
+  dt_ctrl( CTRL_flush );
+  dt_waitbit( STAT_dma_ready );
+  outb_p( DMA_sync, iobase+4 );
+  outb_p( 0, iobase+4 );
+  dma_state ^= STAT_dma_state;
+  while( dt_getstatus( ) & STAT_flushing ) dt_delay( 100 );
+  return 0;
+}
+
+static int dt_sendbuff( char *src, int len )
+{
+  while( len-- ){
+    if( ! dt_wait_dma( ) ) return -1;
+    if( ! (dt_getstatus( ) & STAT_rr_char) ) break;
+    outb_p( DMA_single_in, iobase+4 );
+    outb_p( *src++, iobase+4 );
+    dma_state ^= STAT_dma_state;
+  }
+  return 0;
+}
+
+unsigned long dt_allocmem( unsigned long paras )
+{
+	unsigned long addr;
+	if( ! dt_wait_dma( ) ) return 0;
+	outb_p( DMA_control, iobase+4 );
+	outb_p( DT_MEM_ALLOC, iobase+4 );
+	dma_state ^= STAT_dma_state;
+	if( ! dt_wait_dma( ) ) return 0;
+	outb_p( paras & 0xFF, iobase+4 );
+	outb_p( (paras>>8) & 0xFF, iobase+4 );
+	dma_state ^= STAT_dma_state;
+	if( ! dt_wait_dma( ) ) return 0;
+	addr = inb_p( iobase+4 );
+	addr |= (inb_p( iobase+4 )<<8);
+	addr += (inb_p( iobase+4 )<<4);
+	addr += (inb_p( iobase+4 )<<12);
+	dma_state ^= STAT_dma_state;
+  return addr;
+}
+
+static int testkernel( void )
+{
+  dt_sendcmd( CMD_sync );
+  if( ! dt_waitbit( STAT_cmd_ready ) ) return -10;
+  has_kernel = ( dt_stat&0x8000 ) ? 1 : 0;
+  if ( verbose ) printf( "testkernel got %x\n", dt_stat );
+  if ( has_kernel ) return 0;
+	dt_delay( 100 );
+  return 1;
+}
+
+static int dt_loadmem( int addr, int len, char *src )
+{
+  char c;
+  int l;
+  if ( verbose ) printf( "dt_loadmem: addr = %08X size = %d\n", addr, len );
+  do {
+    l = len;
+    if ( l >= 0xc000 ) l = 0xc000;
+    len -= l;
+    if( ! dt_wait_dma( ) ) return -1;
+    outb_p( DMA_control, iobase+4 );
+    outb_p( DT_LOAD_MEM, iobase+4 );
+    dma_state ^= STAT_dma_state;
+    if( ! dt_wait_dma( ) ) return -2;
+    outb_p( addr & 0xFF, iobase+4 );
+    outb_p( (addr>>8) & 0xFF, iobase+4 );
+    outb_p( (addr>>16) & 0xFF, iobase+4 );
+    outb_p( (addr>>24) & 0xFF, iobase+4 );
+    outb_p( l & 0xFF, iobase+4 );
+    outb_p( (l>>8) & 0xFF, iobase+4 );
+    dma_state ^= STAT_dma_state;
+    if( ! dt_wait_dma( ) ) return -3;
+    addr += l;
+    while( l-- ){
+      c = *src++;
+      outb_p( c, iobase+4 );
+    }
+    dma_state ^= STAT_dma_state;
+  } while ( len > 0 );
+  return 0;
+}
+
+unsigned int loadfile ( char *filename )
+{
+  int i, header_size;
+  unsigned int total_paras;
+  long fix;
+  infd = open ( filename, O_RDONLY );
+  if ( infd == -1 ) {
+      perror ( "Opening file: " );
+      return 0;
+    }
+  read ( infd, &header, sizeof ( struct dos_exe_header ) );
+  if ( header.id != 0x5a4d ) {
+      fprintf ( stderr, "Invalid header file format\n" );
+      fprintf ( stderr, "Want 0x5a4d, got 0x%x\n", header.id );
+      return 0;
+    }
+  if ( header.relen > MAX_FIXUPS ) {
+      fprintf ( stderr, "Too many fixups\n" );
+      return 0;
+    }
+  lseek ( infd, ( long ) header.reloc, SEEK_SET );
+  read ( infd, fixups, sizeof ( struct dos_reloc ) * header.relen );
+  header_size = header.hsize * 16;
+  lseek ( infd, ( long )header_size, SEEK_SET );
+  image_len = ( ( header.pages-1 )*512 ) + ( header.rem- header_size );
+  total_paras =  ( image_len >> 4 ) + header.hmin + 16;
+  read ( infd, read_buff, image_len );
+  close( infd );
+  return total_paras;
+}
+
+static int loadkernel( char *filename )
+{
+  int segfix = 0x40, fix, i;
+  int ipval, csval;
+  if ( has_kernel ) return 0;
+  if ( !loadfile( filename ) ) return -1;
+  header.csval += segfix;
+  header.ssval += segfix;
+  if ( verbose ) {
+      printf ( "Loading kernel of %ld bytes ( %d relocs )\n",
+	      image_len, header.relen );
+      printf ( "    cs:ip == %04x:%04x   ss:sp == %04x:%04x\n",
+	      header.csval, header.ipval, header.ssval, header.spval );
+    }
+  for ( i = 0; i < header.relen; i++ ) {
+      fix = ( fixups[i].segment << 4 ) + fixups[i].offset;
+      ( *( unsigned int * ) &read_buff[fix] ) += segfix;
+    }
+  csval = header.csval;
+  ipval = header.ipval;
+  dt_sendcmd_wait( MODULE_reset, MODULE_init );
+  dt_sendcmd( CMD_reset );
+  if( dt_getstatus( ) == MODULE_self_test ){
+    if( ! dt_waitmode( MODULE_init ) ) return -1;
+  }
+  if ( !dt_sendcmd_wait( CMD_reset, MODE_status ) ) return -2;
+  if ( !dt_sendcmd_wait( CMD_sync, MODE_error ) ) return -3;
+  if ( !dt_sendcmd_wait( CMD_reset, MODE_status ) ) return -4;
+  if ( verbose ) printf( "card is ready\n" );
+  dt_sendcmd( CMD_dma );
+  if( ! dt_waitbit( STAT_dma_ready ) ) return -5;
+  if( ( i = dt_loadmem( 0x00000400, image_len, read_buff ) ) ) {
+   fprintf( stderr, "kernel load failed, status %d\n", i );
+    return -6;
+  }
+  dt_delay( 100 );
+  /* the kernel is loaded, start it */
+  if ( !dt_sendcmd_wait( CMD_reset, MODE_status ) ) return -7;
+  dt_sendcmd( CMD_dma+1 );   /**xxx**/
+	dt_delay( 100 );
+  if( ! dt_waitbit( STAT_dma_ready ) ) return-8;
+  outb_p( DMA_control, iobase+4 );
+  outb_p( DT_START_TASK, iobase+4 );
+	dt_delay( 100 );
+  outb_p( ipval & 0xFF, iobase+4 );
+  outb_p( (ipval>>8) & 0xFF, iobase+4 );
+  outb_p( csval & 0xFF, iobase+4 );
+  outb_p( (csval>>8) & 0xFF, iobase+4 );
+	if( ! dt_waitmode( 0xc001 ) ) return -9;
+  if ( verbose ) {
+    printf( "done loading kernel\n" );
+  }
+  return testkernel( );
+}
+
+int loaddict ( char *filename, char *name, int type )
+{
+  int i, read_index, read_size, act_size;
+  unsigned short *index_fix, seg_fix;
+  unsigned long entries, index, dic_bytes, dic_addr;
+  unsigned int total_paras;
+  unsigned long param, l;
+  infd = open ( filename, O_RDONLY );
+  if ( infd == -1 ) {
+      perror ( filename );
+      return -1;
+    }
+/* read in the entry count and the actual entry size excluding the
+ * index table ( which is entries * 4 ) ...  */
+  read ( infd, &entries, 4 );
+  read ( infd, &dic_bytes, 4 );
+  if ( verbose )
+    printf ( "Loading %s dictionary of %lu entries, %lu bytes.\n",
+	    name, entries, dic_bytes );
+  total_paras = ( ( ( entries * 4 ) + dic_bytes ) >> 4 ) + 2;
+  if ( verbose )
+    printf ( "Allocating %d paragraphs of free ram ...\n", total_paras );
+  l = dt_allocmem( total_paras );
+  if ( l == 0 ) {
+      perror ( "Error requesting memory from speech device" );
+      return -1;
+    }
+  seg_fix = ( l >> 4 ) & 0xffff;
+  dic_addr = l;
+  index = entries;
+  index_fix = ( unsigned short * ) &read_buff[0];
+  if ( verbose )
+    printf ( "Index table starts at %lx\n", l );
+  read_index = index*4;
+  act_size = read ( infd, read_buff, read_index );
+  if ( act_size != read_index ) {
+    fprintf ( stderr, "\nError reading indexes\n" );
+    fprintf ( stderr, "    exp : %d  act : %d\n", read_index * 4, act_size );
+    return -1;
+  }
+  for ( i = 1; i < index * 2; i += 2 )
+    index_fix[i] += seg_fix;
+  if( ( i = dt_loadmem( l, read_index, read_buff ) ) ) {
+    fprintf ( stderr, "\nError loading indexes at 0x%lX: i %d\n",
+      l, i );
+    return -1;
+  }
+  l += read_index;
+/* now, load up the dictionary bytes ...  */
+  if ( verbose )
+    printf ( "Dictionary text starts at %lx\n", l );
+  read_size = dic_bytes;
+  if ( ( act_size = read ( infd, read_buff, read_size ) ) != read_size ) {
+    fprintf ( stderr, "\nError reading dictionary text!\n" );
+    fprintf ( stderr, "asked : %d  actual : %d\n", act_size, read_size );
+    return -1;
+  }
+  if( ( i = dt_loadmem( l, read_size, read_buff ) ) ) {
+    fprintf ( stderr, "\nError loading dictionary at 0x%lX: status %d\n",
+      l, i );
+    return -1;
+  }
+  if( ! dt_wait_dma( ) ) return -1;
+  outb_p( DMA_control, iobase+4 );
+  outb_p( DT_SET_DIC, iobase+4 );
+	dma_state ^= STAT_dma_state;
+  if( ! dt_wait_dma( ) ) return -1;
+  l  = dic_addr;
+	l = ((l << 12) & 0xFFFF0000) + (l & 0x0000000F);
+  outb_p( l & 0xFF, iobase+4 );
+  outb_p( (l>>8) & 0xFF, iobase+4 );
+  outb_p( (l>>16) & 0xFF, iobase+4 );
+  outb_p( (l>>24) & 0xFF, iobase+4 );
+  l = entries;
+  outb_p( l & 0xFF, iobase+4 );
+  outb_p( (l>>8) & 0xFF, iobase+4 );
+  outb_p( (l>>16) & 0xFF, iobase+4 );
+  outb_p( (l>>24) & 0xFF, iobase+4 );
+	l = type;
+  outb_p( l & 0xFF, iobase+4 );
+  outb_p( (l>>8) & 0xFF, iobase+4 );
+	dma_state ^= STAT_dma_state;
+  close ( infd );
+  if ( verbose ) printf( "dictionary load complete\n" );
+  return 0;
+}
+
+int loadexe ( char *filename )
+{
+  unsigned int load_addr = 0, seg_fix;
+  int i, read_size;
+  int ipval, csval;
+  long fix;
+  unsigned long total_paras;
+  total_paras = loadfile ( filename );
+  if ( total_paras == 0 ) return -1;
+  load_addr = dt_allocmem( total_paras );
+  if ( load_addr == 0 ) {
+    fprintf ( stderr, "Error allocating memory on card: " );
+    return -1;
+  }
+  seg_fix = ( load_addr >> 4 ) & 0xffff;
+  if ( verbose ) {
+      printf ( "Loading %s %ld bytes ( %d relocs )\n",
+	      filename, image_len, header.relen );
+      printf ( "Allocating %ld bytes of free ram at %05x\n",
+	      ( long ) header.hmin * 16, load_addr );
+      printf ( "Total memory taken is %ld bytes\n", ( long ) total_paras * 16 );
+      printf ( "    cs:ip == %04x:%04x   ss:sp == %04x:%04x\n",
+	      header.csval + seg_fix, header.ipval, header.ssval + seg_fix, header.spval );
+    }
+    for ( i = 0; i < header.relen; i++ ) {
+	fix = ( ( long ) fixups[i].segment << 4 ) + ( long ) fixups[i].offset;
+	( *( unsigned int * ) &read_buff[fix] ) += seg_fix;
+    	 }
+  if( ( i = dt_loadmem( load_addr, image_len, read_buff ) ) ) {
+    fprintf ( stderr, "Error loading speech device at 0x%lX: status %d\n",
+      load_addr, i );
+    return -1;
+  }
+  csval = header.csval + seg_fix;
+  ipval = header.ipval;
+  if( ! dt_wait_dma( ) ) return -1;
+  outb_p( DMA_control, iobase+4 );
+  outb_p( DT_START_TASK, iobase+4 );
+	dma_state ^= STAT_dma_state;
+  if( ! dt_wait_dma( ) ) return -1;
+  outb_p( ipval & 0xFF, iobase+4 );
+  outb_p( (ipval>>8) & 0xFF, iobase+4 );
+  outb_p( csval & 0xFF, iobase+4 );
+  outb_p( (csval>>8) & 0xFF, iobase+4 );
+	dma_state ^= STAT_dma_state;
+  return 0;
+}
+
+void release_io( void )
+{
+  ioperm( (long)iobase, 8, 0 );
+  ioperm( (long)0x0080, 1, 0 );
+  if ( read_buff ) free( read_buff );
+}
+
+parseparm( char *parm, char *value )
+{
+  char *cp = parm+strlen( parm );
+  while ( --cp > parm ) if ( *cp > ' ' ) break;
+  cp[1] = '\0';
+  if ( !strcmp( parm, "io" ) ) {
+    long io = strtol( value, 0, 0 );
+    if ( io >= 0x100 && io <= 0x350 ) {
+      iobase = (u_short)io;
+      return;
+    }
+    fprintf( stderr, "invalid io value %s\n", value );
+    exit( 1 );
+  } else if ( !strcmp( parm,"verbose" ) ) {
+    verbose = atoi( value );
+  }
+}
+
+do_test( void )
+{
+  char buffer[512];
+  int len;
+  dma_state = dt_getstatus( ) & STAT_dma_state;
+  while ( fgets( buffer, 510, stdin ) ) {
+    len = strlen( buffer );
+    if ( len == 1 ) dt_flush( );
+    else {
+      if ( buffer[len-1] == '\n' ) buffer[len-1] = '\013';
+      dt_sendbuff( buffer, len );
+    }
+  }
+  *buffer = '\013';
+  dt_sendbuff( buffer, 1 );
+}
+
+int main ( int argc, char **argv )
+{
+  char name[80], *cp;
+  char *dirname = 0, *confname = "dec_pc.conf";
+  char *init_msg = "[:ra 360] dec pc initialized\011";
+  FILE *confile;
+  struct stat statbuf;
+  int maxsize = 0, status = 0;
+  while ( --argc > 0 ) {
+    argv++;
+    if ( !strcmp( *argv, "-v" ) ) verbose = 1;
+    else if ( !strcmp( *argv, "-t" ) ) intest = 1;
+    else dirname = *argv;
+  }
+  if ( !dirname ) dirname = "/usr/local/lib/dec_pc";
+  if ( chdir( dirname ) != 0 ) {
+    fprintf( stderr, "cannot chdir to %s\n", dirname );
+    exit( 1 );
+  }
+  if ( !( confile = fopen( confname, "r" ) ) ) {
+    fprintf( stderr, "could not open %s", confname );
+    exit( 1 );
+  }
+  while ( fgets( name, 80, confile ) ) {
+    cp = strchr( name, '\n' );
+    if ( cp ) *cp = '\0';
+    if ( ( cp = strchr( name, '=' ) ) ) {
+      *cp++ = '\0';
+      parseparm( name, cp );
+      continue;
+    }
+    if ( stat( name, &statbuf ) != 0 ) {
+      fprintf( stderr, "cannot stat %s\n", name );
+      exit( 1 );
+    }
+    if ( statbuf.st_size > maxsize ) maxsize = statbuf.st_size;
+  }
+  rewind( confile );
+  if ( ioperm( (long)0x0080, 1, 1 ) || ioperm( (long)iobase, 8, 1 ) ) {
+    fprintf( stderr, "could not get ioperm\n" );
+    exit( 1 );
+  }
+  atexit( release_io );
+  if ( testkernel( ) == 0 ) {
+    if ( intest ) do_test( );
+    else fprintf( stderr, "kernel already loaded\n" );
+    exit( 0 );
+  }
+  read_buff = malloc(  maxsize );
+  if ( !read_buff ) {
+    fprintf( stderr, "cannot malloc %d bytes\n", maxsize );
+    exit( 1 );
+  }
+  while ( fgets( name, 80, confile ) && !status ) {
+    cp = strchr( name, '\n' );
+    if ( cp ) *cp = '\0';
+    if ( strchr( name, '=' ) ) continue; /* a parameter */
+    if ( !( cp = strchr( name, '.' ) ) ) continue;
+    cp++;
+    if ( !strcmp ( cp, "dic" ) ) {
+      status = loaddict ( name, "primary", PRIMARY_DIC );
+    } else if ( !strcmp ( cp, "dtu" ) ) {
+      status = loaddict ( name, "user", USER_DIC );
+    } else if ( !strcmp ( cp, "dta" ) ) {
+      status = loaddict ( name, "abbreviation file", ABBREV_DIC );
+    } else if ( !strcmp ( cp, "exe" ) ) {
+      status = loadexe ( name );
+    } else if ( !strcmp ( cp, "sys" ) ) {
+      status = loadkernel ( name );
+    }
+  }
+  if ( status ) fprintf( stderr, "status %d\n", status );
+  fclose( confile );
+  if ( status ) exit( status );
+  dt_sendbuff( init_msg, strlen( init_msg ) );
+  sleep( 1 );
+  if ( intest ) do_test( );
+  exit( 0 );
+}
diff -puN /dev/null drivers/char/speakup/dtload.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/dtload.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,57 @@
+/*
+ * This is the DECtalk PC firmware loader for the Linux kernel, version 1.0
+ *
+ * Original 386BSD source:
+ *      Copyright (c) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
+ *
+ * Adapted for Linux:
+ *      Copyright (c) 1997 Nicolas Pitre <nico@cam.org>
+ *
+ * Adapted for speakup:
+ *      Copyright (c) 2003 David Borowski <david575@golden.net>
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#define	MAX_FIXUPS	512	  	/* maximum fixups per exe */
+/*
+ *  msdos .exe files will look like ...
+ */
+
+struct dos_exe_header {
+	unsigned short id;		/* Linker's signature, must be 0x5a4d */
+	unsigned short rem;		/* length of image mod 512 */
+	unsigned short pages;		/* length of image in pages of 512 bytes */
+	unsigned short relen;		/* number of relocation items */
+	unsigned short hsize;		/* header size in paragraphs of 16 bytes */
+	unsigned short hmin;		/* min # of paragraphs above prog end */
+	unsigned short hmax;
+	unsigned short ssval;
+	unsigned short spval;		/* to be loaded in sp */
+	unsigned short	checksum;
+	unsigned short	ipval;		/* to be loaded in ip */
+	unsigned short	csval;  	/* segment offset to code */
+	unsigned short	reloc;		/* location of relocation items	*/
+	unsigned short	ovrlay;		/* overlay number */
+};
+
+/*  a dos relocation element looks like */
+
+struct dos_reloc {
+	short int offset, segment;
+};
diff -puN /dev/null drivers/char/speakup/dtpc_reg.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/dtpc_reg.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,132 @@
+/*
+ * This is the DECtalk PC register constants (from DEC's DOS driver)
+ *
+ * Original code:
+ *      Copyright (c) by Digital Equipment Corp.
+ *
+ * 386BSD DECtalk PC driver:
+ *      Copyright (c) 1996 Brian Buhrow <buhrow@lothlorien.nfbcal.org>
+ *
+ * Linux DECtalk PC driver:
+ *      Copyright (c) 1997 Nicolas Pitre <nico@cam.org>
+ *
+ * speakup DECtalk PC driver:
+ *      Copyright (c) 2003 David Borowski <david575@golden.net>
+ *
+ * All rights reserved.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ *  port interface defs ... used by dtpc.c
+ */
+
+#define	MODULE_init		0x0dec		/* module in boot code */
+#define	MODULE_self_test	0x8800		/* module in self-test */
+#define	MODULE_reset		0xffff		/* reinit the whole module */
+
+#define	MODE_mask		0xf000		/* mode bits in high nibble */
+#define	MODE_null		0x0000
+#define	MODE_test		0x2000		/* in testing mode */
+#define	MODE_status		0x8000
+#define	STAT_int		0x0001		/* running in interrupt mode */
+#define	STAT_tr_char	0x0002		/* character data to transmit */
+#define	STAT_rr_char	0x0004		/* ready to receive char data */
+#define	STAT_cmd_ready	0x0008		/* ready to accept commands */
+#define	STAT_dma_ready	0x0010		/* dma command ready */
+#define	STAT_digitized	0x0020		/* spc in digitized mode */
+#define	STAT_new_index	0x0040		/* new last index ready */
+#define	STAT_new_status	0x0080		/* new status posted */
+#define	STAT_dma_state	0x0100		/* dma state toggle */
+#define	STAT_index_valid	0x0200		/* indexs are valid */
+#define	STAT_flushing	0x0400		/* flush in progress */
+#define	STAT_self_test	0x0800		/* module in self test */
+#define	MODE_ready		0xc000		/* module ready for next phase */
+#define	READY_boot		0x0000
+#define	READY_kernel	0x0001
+#define	MODE_error		0xf000
+
+#define	CMD_mask			0xf000		/* mask for command nibble */
+#define	CMD_null			0x0000		/* post status */
+#define	CMD_control		0x1000		/* hard control command */
+#define	CTRL_mask		0x0F00	/*   mask off control nibble */
+#define	CTRL_data		0x00FF	/*   madk to get data byte */
+#define	CTRL_null		0x0000	/*   null control */
+#define	CTRL_vol_up		0x0100	/*   increase volume */
+#define	CTRL_vol_down		0x0200	/*   decrease volume */
+#define	CTRL_vol_set		0x0300	/*   set volume */
+#define	CTRL_pause		0x0400	/*   pause spc */
+#define	CTRL_resume		0x0500	/*   resume spc clock */
+#define	CTRL_resume_spc		0x0001	/*   resume spc soft pause */
+#define	CTRL_flush		0x0600	/*   flush all buffers */
+#define	CTRL_int_enable	0x0700	/*   enable status change ints */
+#define	CTRL_buff_free		0x0800	/*   buffer remain count */
+#define	CTRL_buff_used		0x0900	/*   buffer in use */
+#define	CTRL_speech		0x0a00	/*   immediate speech change */
+#define		CTRL_SP_voice		0x0001	/*      voice change */
+#define		CTRL_SP_rate		0x0002	/*      rate change */
+#define		CTRL_SP_comma		0x0003	/*      comma pause change */
+#define		CTRL_SP_period		0x0004	/*      period pause change */
+#define		CTRL_SP_rate_delta	0x0005	/*	  delta rate change */
+#define		CTRL_SP_get_param	0x0006	/*      return the desired parameter */
+#define	CTRL_last_index	0x0b00	/*   get last index spoken */
+#define	CTRL_io_priority	0x0c00	/*   change i/o priority */
+#define	CTRL_free_mem		0x0d00	/*   get free paragraphs on module */
+#define	CTRL_get_lang		0x0e00	/*   return bit mask of loaded languages */
+#define	CMD_test			0x2000		/* self-test request */
+#define	TEST_mask		0x0F00	/* isolate test field */
+#define	TEST_null		0x0000	/* no test requested */
+#define	TEST_isa_int		0x0100	/* assert isa irq */
+#define	TEST_echo		0x0200	/* make data in == data out */
+#define	TEST_seg			0x0300	/* set peek/poke segment */
+#define	TEST_off			0x0400	/* set peek/poke offset */
+#define	TEST_peek		0x0500	/* data out == *peek */
+#define	TEST_poke		0x0600	/* *peek == data in */
+#define	TEST_sub_code		0x00FF	/* user defined test sub codes */
+#define	CMD_id			0x3000		/* return software id */
+#define	ID_null			0x0000	/* null id */
+#define	ID_kernel		0x0100	/* kernel code executing */
+#define	ID_boot			0x0200	/* boot code executing */
+#define	CMD_dma			0x4000		/* force a dma start */
+#define	CMD_reset		0x5000		/* reset module status */
+#define	CMD_sync			0x6000		/* kernel sync command */
+#define	CMD_char_in		0x7000		/* single character send */
+#define	CMD_char_out		0x8000		/* single character get */
+#define	CHAR_count_1		0x0100	/*    one char in cmd_low */
+#define	CHAR_count_2		0x0200	/*	the second in data_low */
+#define	CHAR_count_3		0x0300	/*	the third in data_high */
+#define	CMD_spc_mode		0x9000		/* change spc mode */
+#define	CMD_spc_to_text	0x0100	/*   set to text mode */
+#define	CMD_spc_to_digit	0x0200	/*   set to digital mode */
+#define	CMD_spc_rate		0x0400	/*   change spc data rate */
+#define	CMD_error		0xf000		/* severe error */
+
+enum {	PRIMARY_DIC	= 0, USER_DIC, COMMAND_DIC, ABBREV_DIC };
+
+#define	DMA_single_in		0x01
+#define	DMA_single_out		0x02
+#define	DMA_buff_in		0x03
+#define	DMA_buff_out		0x04
+#define	DMA_control		0x05
+#define	DT_MEM_ALLOC		0x03
+#define	DT_SET_DIC		0x04
+#define	DT_START_TASK		0x05
+#define	DT_LOAD_MEM		0x06
+#define	DT_READ_MEM		0x07
+#define	DT_DIGITAL_IN		0x08
+#define	DMA_sync		0x06
+#define	DMA_sync_char		0x07
diff -puN /dev/null drivers/char/speakup/genmap.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/genmap.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,204 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <linux/version.h>
+#include <ctype.h>
+
+int get_define(void);
+
+#define MAXKEYS 512
+#define MAXKEYVAL 160
+#define HASHSIZE 101
+#define is_shift -3
+#define is_spk -2
+#define is_input -1
+typedef struct st_key_init t_key_init;
+struct st_key_init {
+	char *name;
+	int value, shift;
+};
+typedef struct st_key t_key;
+struct st_key {
+	char *name;
+	t_key *next;
+	int value, shift;
+};
+unsigned char key_data[MAXKEYVAL][16], *kp;
+
+#include "mapdata.h"
+t_key key_table[MAXKEYS];
+t_key *extra_keys = key_table+HASHSIZE;
+char buffer[256], filename[256];
+FILE *infile;
+char delims[] = "\t\n ";
+char *def_name, *def_val, *cp;
+int map_ver = 119; /* an arbitrary number so speakup can check */
+int lc, shift_table[17];
+int max_states = 1, flags = 0;
+/* flags reserved for later, maybe for individual console maps */
+
+void open_input( char *name )
+{
+	strcpy( filename, name );
+	if ( ( infile = fopen( filename, "r" ) ) == 0 ) {
+		fprintf( stderr, "can't open %s, version %d\n", filename, LINUX_VERSION_CODE );
+		exit( 1 );
+	}
+	lc = 0;
+}
+
+int
+oops( char *msg, char *info )
+{
+	if ( info == NULL ) info = " ";
+	fprintf( stderr, "error: file %s line %d\n", filename, lc );
+	fprintf( stderr, "%s %s\n", msg, info );
+	exit( 1 );
+}
+
+t_key *hash_name( char *name )
+{
+	u_char *pn = (u_char *)name;
+	int hash = 0;
+	while ( *pn ) {
+		hash = ( hash * 17 ) & 0xfffffff;
+	if ( isupper( *pn ) ) *pn = tolower( *pn );
+		hash += ( int )*pn;
+		pn++;
+	}
+	hash %= HASHSIZE;
+	return &key_table[hash];
+}
+
+t_key *find_key( char *name )
+{
+	t_key *this = hash_name( name );
+	while ( this ) {
+		if ( !strcmp( name, this->name ) ) return this;
+		this = this->next;
+	}
+	return this;
+}
+
+t_key *add_key( char *name, int value, int shift )
+{
+	t_key *this = hash_name( name );
+	if ( extra_keys-key_table >= MAXKEYS )
+		oops( "out of key table space, enlarge MAXKEYS", NULL );
+	if ( this->name != NULL ) {
+		while ( this->next ) {
+			if ( !strcmp( name, this->name ) )
+				oops( "attempt to add duplicate key", name );
+			this = this->next;
+		}
+		this->next = extra_keys++;
+		this = this->next;
+	}
+	this->name = strdup( name );
+	this->value = value;
+	this->shift = shift;
+	return this;
+}
+
+int get_shift_value( int state )
+{
+	int i;
+	for ( i = 0; shift_table[i] != state; i++ ) {
+		if ( shift_table[i] == -1 ) {
+			if ( i >= 16 )
+				oops( "too many shift states", NULL );
+			shift_table[i] = state;
+			max_states = i+1;
+		break;
+	}
+	}
+	return i;
+}
+
+int
+main( int argc, char *argv[] )
+{
+	int value, shift_state, i, spk_val = 0, lock_val = 0;
+	int max_key_used = 0, num_keys_used = 0;
+	t_key *this;
+	t_key_init *p_init;
+char *argpath, *argname, *argcopy;
+
+	bzero( key_table, sizeof( key_table ) );
+	bzero( key_data, sizeof( key_data ) );
+	shift_table[0] = 0;
+	for ( i = 1; i <= 16; i++ ) shift_table[i] = -1;
+	if ( argc < 2 ) {
+		fputs( "usage: genmap filename\n", stderr );
+		exit( 1 );
+	}
+  for ( p_init = init_key_data; p_init->name[0] != '.'; p_init++ )
+		add_key( p_init->name, p_init->value, p_init->shift );
+	open_input( argv[1] );
+	while ( fgets( buffer, 250, infile ) ) {
+		lc++;
+		value = shift_state = 0;
+		cp = strtok( buffer, delims );
+		if ( *cp == '#' ) continue;
+		while ( cp ) {
+			if ( *cp == '=' ) break;
+			this = find_key( cp );
+			if ( this == NULL )
+				oops( "unknown key/modifier", cp );
+			if ( this->shift == is_shift ) {
+				if ( value )
+					oops( "modifiers must come first", cp );
+				shift_state += this->value;
+			} else if ( this->shift == is_input )
+				value = this->value;
+			else oops( "bad modifier or key", cp );
+			cp = strtok( 0, delims );
+		}
+		if ( !cp ) oops( "no = found", NULL );
+		cp = strtok( 0, delims );
+		if ( !cp ) oops( "no speakup function after =", NULL );
+		this = find_key( cp );
+		if ( this == NULL || this->shift != is_spk )
+			oops( "invalid speakup function", cp );
+		i = get_shift_value( shift_state );
+		if ( key_data[value][i] ) {
+			while ( --cp > buffer )
+				if ( !*cp ) *cp = ' ';
+			oops( "two functions on same key combination", cp );
+		}
+		key_data[value][i] = (char)this->value;
+		if ( value > max_key_used ) max_key_used = value;
+	}
+	fclose( infile );
+	this = find_key( "spk_key" );
+	if ( this ) spk_val = this->value;
+	this = find_key( "spk_lock" );
+	if ( this ) lock_val = this->value;
+	for ( lc = 1; lc <= max_key_used; lc++ ) {
+		kp = key_data[lc];
+		if ( !memcmp( key_data[0], kp, 16 ) ) continue;
+		num_keys_used++;
+		for ( i = 0; i < max_states; i++ ) {
+			if ( kp[i] != spk_val&& kp[i] != lock_val ) continue;
+			shift_state = shift_table[i];
+			if ( ( shift_state&16 ) ) continue;
+			shift_state = get_shift_value( shift_state+16 );
+			kp[shift_state] = kp[i];
+/* fill in so we can process the key up, as spk bit will be set */
+		}
+	}
+	printf( "\t%d, %d, %d,\n\t", map_ver, num_keys_used, max_states );
+	for ( i = 0; i < max_states; i++ )
+		printf( "%d, ", shift_table[i] );
+	printf( "%d,", flags );
+	for ( lc = 1; lc <= max_key_used; lc++ ) {
+		kp = key_data[lc];
+		if ( !memcmp( key_data[0], kp, 16 ) ) continue;
+		printf( "\n\t%d,", lc );
+		for ( i = 0; i < max_states; i++ )
+			printf( " %d,", (unsigned int)kp[i] );
+	}
+	printf( "\n\t0, %d\n", map_ver );
+	exit( 0 );
+}
diff -puN /dev/null drivers/char/speakup/Kconfig
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/Kconfig	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,210 @@
+menu "Speakup console speech"
+config SPEAKUP
+	tristate "Build speakup console speech"
+	---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 evrything 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, and transport.
+
+		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.
+
+
+		The Dectalk pc driver can only be built as a module, and
+		requires software to be pre-loaded on to the card before
+		the module can be loaded.  See the decpc choice below
+		for more details.
+
+		If you are not a blind person, or don't have access to
+		one of the listed synthesizers, you should say n.
+
+config SPEAKUP_ACNTSA
+	depends on SPEAKUP
+	tristate "Accent SA, acntsa"
+	---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_ACNTPC
+	depends on SPEAKUP
+	tristate "Accent PC, acntpc"
+	---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_APOLLO
+	depends on SPEAKUP
+	tristate "Apollo, apollo"
+	---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_AUDPTR
+	depends on SPEAKUP
+	tristate "Audapter, audptr"
+	---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_BNS
+	depends on SPEAKUP
+	tristate "Braille 'n' Speak, bns"
+	---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_DECTLK
+	depends on SPEAKUP
+	tristate "DECtalk Express, dectlk"
+	---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_DECEXT
+	depends on SPEAKUP
+	tristate "DECtalk External (old), decext"
+	---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_DECPC
+	depends on SPEAKUP
+	tristate "DECtalk PC (big ISA card), decpc"
+	---help---
+
+		This is the Speakup driver for the DecTalk PC (full
+		length ISA) synthesizer.  You can say  m to build it as
+		a module.  See the configuration help on the Speakup
+		choice above for more info.
+
+		In order to use the DecTalk PC driver, you must download
+		the dec_pc.tgz file from linux-speakup.org.  It is in
+		the pub/linux/goodies directory.  The dec_pc.tgz file
+		contains the software which must be pre-loaded on to the
+		DecTalk PC board in order to use it with this driver.
+		This driver must be built as a module, and can not be
+		loaded until the file system is mounted and the DecTalk
+		PC software has been pre-loaded on to the board.
+
+		See the README file in the dec_pc.tgz file for more
+		details.
+
+config SPEAKUP_DTLK
+	depends on SPEAKUP
+	tristate "DoubleTalk PC, dtlk"
+	---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_KEYPC
+	depends on SPEAKUP
+	tristate "Keynote Gold PC, keypc"
+	---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_LTLK
+	depends on SPEAKUP
+	tristate "DoubleTalk LT or LiteTalk, ltlk"
+---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_SFTSYN
+	depends on SPEAKUP
+	tristate "Software synthesizers, sftsyn"
+---help---
+
+		This is the software synthesizer device node.  It will
+		register a device /dev/sftsyn which midware programs
+		and speech
+		daemons may open and read to provide kernel output to
+		software synths
+		such as festival, flite, tuxtalk and so forth.  You
+		can select 'y' or
+		'm' to have it built-in to the kernel or loaded as a module.
+
+config SPEAKUP_SPKOUT
+	depends on SPEAKUP
+	tristate "Speak Out, spkout"
+	---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_TXPRT
+	depends on SPEAKUP
+	tristate "Transport, txprt"
+	---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.
+
+if SPEAKUP != n
+	comment 'Enter the 3 to 6 character keyword from the list above, or none for no default synthesizer on boot up.'
+	depends on SPEAKUP
+endif
+
+config SPEAKUP_DEFAULT
+	string "Choose Default synthesizer for Speakup"
+	default "none"
+
+endmenu
diff -puN /dev/null drivers/char/speakup/keyinfo.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/keyinfo.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,119 @@
+/* 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
+*/
+
+enum { /* var_ids */
+	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, FREQ, LANG,
+	CAPS_START, CAPS_STOP,
+	MAXVARS
+};
+
+#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 SPKUP_MAX_FUNC 0x2f /* 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
diff -puN /dev/null drivers/char/speakup/Makefile
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/Makefile	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,36 @@
+#
+# Makefile for the speakup speech output system.
+#
+
+obj-m = speakup_keyhelp.o
+speakupmain-objs := speakup.o speakup_drvcommon.o
+
+obj-$(CONFIG_SPEAKUP)		+= speakupmain.o
+obj-$(CONFIG_SPEAKUP_ACNTPC)	+= speakup_acntpc.o
+obj-$(CONFIG_SPEAKUP_ACNTSA)	+= speakup_acntsa.o
+obj-$(CONFIG_SPEAKUP_APOLLO)	+= speakup_apollo.o
+obj-$(CONFIG_SPEAKUP_AUDPTR)	+= speakup_audptr.o
+obj-$(CONFIG_SPEAKUP_BNS)	+= speakup_bns.o
+obj-$(CONFIG_SPEAKUP_DECEXT)	+= speakup_decext.o
+obj-$(CONFIG_SPEAKUP_DECPC)	+= speakup_decpc.o
+obj-$(CONFIG_SPEAKUP_DECTLK)	+= speakup_dectlk.o
+obj-$(CONFIG_SPEAKUP_DTLK)	+= speakup_dtlk.o
+obj-$(CONFIG_SPEAKUP_KEYPC)	+= speakup_keypc.o
+obj-$(CONFIG_SPEAKUP_LTLK)	+= speakup_ltlk.o
+obj-$(CONFIG_SPEAKUP_SFTSYN)	+= speakup_sftsyn.o
+obj-$(CONFIG_SPEAKUP_SPKOUT)	+= speakup_spkout.o
+obj-$(CONFIG_SPEAKUP_TXPRT)	+= speakup_txprt.o
+
+#speakupmain.o:speakup.o speakup_drvcommon.o
+#	ld -r -o speakupmain.o speakup.o speakup_drvcommon.o
+
+$(obj)/speakupmap.h: $(src)/speakupmap.map $(src)/genmap
+	$(src)/genmap $(src)/speakupmap.map >$@
+
+$(obj)/mapdata.h: $(src)/keyinfo.h $(src)/makemapdata
+	$(src)/makemapdata >$@
+
+$(obj)/genmap: $(obj)/mapdata.h
+
+HOSTCFLAGS := -Iinclude -I/usr/include
+hostprogs-y := makemapdata genmap
diff -puN /dev/null drivers/char/speakup/makemapdata.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/makemapdata.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,156 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <linux/version.h>
+#include <ctype.h>
+
+int get_define(void);
+
+#define MAXKEYS 512
+#define MAXKEYVAL 160
+#define HASHSIZE 101
+#define is_shift -3
+#define is_spk -2
+#define is_input -1
+typedef struct st_key t_key;
+struct st_key {
+	char *name;
+	t_key *next;
+	int value, shift;
+};
+
+t_key key_table[MAXKEYS];
+t_key *extra_keys = key_table+HASHSIZE;
+char buffer[256], filename[256];
+FILE *infile;
+char delims[] = "\t\n ";
+char *dir_name, *def_name, *def_val, *cp;
+int lc;
+
+void open_input( char *name )
+{
+	sprintf( filename, "%s/%s", dir_name, name );
+	if ( ( infile = fopen( filename, "r" ) ) == 0 ) {
+		fprintf( stderr, "can't open %s\n", filename );
+		exit( 1 );
+	}
+	lc = 0;
+}
+
+int
+oops( char *msg, char *info )
+{
+	if ( info == NULL ) info = " ";
+	fprintf( stderr, "error: file %s line %d\n", filename, lc );
+	fprintf( stderr, "%s %s\n", msg, info );
+	exit( 1 );
+}
+
+int get_define( )
+{
+	while ( fgets( buffer, 250, infile ) ) {
+		lc++;
+		if ( strncmp( buffer, "#define", 7 ) ) continue;
+		strtok( buffer, delims );
+		def_name = strtok( 0, delims );
+		def_val = strtok( 0, delims );
+		if ( def_val != NULL ) return 1;
+	}
+	fclose( infile );
+	infile = 0;
+	return 0;
+}
+
+t_key *hash_name( char *name )
+{
+	u_char *pn = (u_char *)name;
+	int hash = 0;
+	while ( *pn ) {
+		hash = ( hash * 17 ) & 0xfffffff;
+	if ( isupper( *pn ) ) *pn = tolower( *pn );
+		hash += ( int )*pn;
+		pn++;
+	}
+	hash %= HASHSIZE;
+	return &key_table[hash];
+}
+
+t_key *find_key( char *name )
+{
+	t_key *this = hash_name( name );
+	while ( this ) {
+		if ( !strcmp( name, this->name ) ) return this;
+		this = this->next;
+	}
+	return this;
+}
+
+t_key *add_key( char *name, int value, int shift )
+{
+	t_key *this = hash_name( name );
+	if ( extra_keys-key_table >= MAXKEYS )
+		oops( "out of key table space, enlarge MAXKEYS", NULL );
+	if ( this->name != NULL ) {
+		while ( this->next ) {
+			if ( !strcmp( name, this->name ) )
+				oops( "attempt to add duplicate key", name );
+			this = this->next;
+		}
+		this->next = extra_keys++;
+		this = this->next;
+	}
+	this->name = strdup( name );
+	this->value = value;
+	this->shift = shift;
+	return this;
+}
+
+int
+main( int argc, char *argv[] )
+{
+	int value, i;
+	t_key *this;
+	dir_name = getenv( "TOPDIR" );
+	if ( !dir_name ) dir_name = "/usr/src/linux";
+	bzero( key_table, sizeof( key_table ) );
+	add_key( "shift",	1, is_shift );
+	add_key( "altgr",	2, is_shift );
+	add_key( "ctrl",	4, is_shift );
+	add_key( "alt",	8, is_shift );
+	add_key( "spk", 16, is_shift );
+	add_key( "double", 32, is_shift );
+	open_input( "include/linux/input.h" );
+	while ( get_define( ) ) {
+		if ( strncmp( def_name, "KEY_", 4 ) ) continue;
+		value = atoi( def_val );
+		if ( value > 0 && value < MAXKEYVAL )
+			add_key(  def_name, value, is_input );
+	}
+	open_input( "drivers/char/speakup/keyinfo.h" );
+	while ( get_define( ) ) {
+		if ( strlen( def_val ) > 5 ) {
+			if ( !( cp = strchr( def_val, '+' ) ) ) continue;
+			*cp++ = '\0';
+			this = find_key( def_val );
+			if ( !this || *cp < '0' || *cp > '9' ) continue;
+			value = this->value+atoi( cp );
+		} else if ( !strncmp( def_val, "0x", 2 ) )
+			sscanf( def_val+2, "%x", &value );
+		else if ( *def_val >= '0' && *def_val <= '9' )
+			value = atoi( def_val );
+		else continue;
+		add_key( def_name, value, is_spk );
+	}
+	printf( "t_key_init init_key_data[] = {\n" );
+	for ( i = 0; i < HASHSIZE; i++ ) {
+		this = &key_table[i];
+		if ( !this->name ) continue;
+		do {
+			printf( "\t\"%s\", %d, %d,\n", this->name, this->value, this->shift );
+			this = this->next;
+		} while ( this );
+	}
+	printf( "\t\".\", 0, 0\n};\n" );
+	exit( 0 );
+}
diff -puN /dev/null drivers/char/speakup/mapdata.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/mapdata.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,238 @@
+t_key_init init_key_data[] = {
+	"key_s", 31, -1,
+	"top_edge", 17, -2,
+	"key_t", 20, -1,
+	"say_first_char", 6, -2,
+	"attrib_bleep_inc", 71, -2,
+	"key_u", 22, -1,
+	"key_grave", 41, -1,
+	"key_v", 47, -1,
+	"key_w", 17, -1,
+	"key_kpasterisk", 55, -1,
+	"key_minus", 12, -1,
+	"key_x", 45, -1,
+	"key_down", 108, -1,
+	"key_y", 21, -1,
+	"key_kpdot", 83, -1,
+	"key_leftmeta", 125, -1,
+	"key_z", 44, -1,
+	"key_volumedown", 114, -1,
+	"say_next_word", 13, -2,
+	"clear_win", 41, -2,
+	"key_rightbrace", 27, -1,
+	"right_edge", 20, -2,
+	"key_scrolllock", 70, -1,
+	"key_comma", 51, -1,
+	"altgr", 2, -3,
+	"say_screen", 23, -2,
+	"key_cut", 137, -1,
+	"say_to_bottom", 30, -2,
+	"edit_most", 35, -2,
+	"key_sleep", 142, -1,
+	"say_phonetic_char", 36, -2,
+	"speakup_quiet", 3, -2,
+	"key_hanja", 123, -1,
+	"say_next_line", 16, -2,
+	"vol_dec", 78, -2,
+	"key_help", 138, -1,
+	"key_xfer", 147, -1,
+	"speakup_goto", 1, -2,
+	"punct_inc", 83, -2,
+	"key_rightctrl", 97, -1,
+	"attrib_bleep_dec", 70, -2,
+	"key_rightshift", 54, -1,
+	"key_linefeed", 101, -1,
+	"key_wakeup", 143, -1,
+	"key_enter", 28, -1,
+	"key_again", 129, -1,
+	"key_file", 144, -1,
+	"key_tab", 15, -1,
+	"speakup_off", 26, -2,
+	"set_win", 40, -2,
+	"key_insert", 110, -1,
+	"key_setup", 141, -1,
+	"key_equal", 13, -1,
+	"tone_inc", 81, -2,
+	"key_hiragana", 91, -1,
+	"key_kpjpcomma", 95, -1,
+	"key_pause", 119, -1,
+	"key_volumeup", 115, -1,
+	"key_f1", 59, -1,
+	"key_hanguel", 122, -1,
+	"double", 32, -3,
+	"key_f2", 60, -1,
+	"key_computer", 157, -1,
+	"key_back", 158, -1,
+	"key_leftctrl", 29, -1,
+	"key_f3", 61, -1,
+	"key_f4", 62, -1,
+	"key_0", 11, -1,
+	"key_f5", 63, -1,
+	"key_yen", 124, -1,
+	"key_copy", 133, -1,
+	"speakup_paste", 5, -2,
+	"key_1", 2, -1,
+	"key_f6", 64, -1,
+	"toggle_cursoring", 46, -2,
+	"key_esc", 1, -1,
+	"key_2", 3, -1,
+	"key_f7", 65, -1,
+	"speakup_parked", 27, -2,
+	"punct_dec", 82, -2,
+	"key_3", 4, -1,
+	"key_f8", 66, -1,
+	"key_4", 5, -1,
+	"key_f9", 67, -1,
+	"key_5", 6, -1,
+	"key_calc", 140, -1,
+	"spell_phonetic", 21, -2,
+	"key_6", 7, -1,
+	"key_7", 8, -1,
+	"key_coffee", 152, -1,
+	"key_mail", 155, -1,
+	"say_attributes", 25, -2,
+	"say_to_right", 32, -2,
+	"key_8", 9, -1,
+	"key_mute", 113, -1,
+	"key_9", 10, -1,
+	"key_katakana", 90, -1,
+	"key_zenkakuhankaku", 85, -1,
+	"key_forward", 159, -1,
+	"key_up", 103, -1,
+	"tone_dec", 80, -2,
+	"key_leftalt", 56, -1,
+	"say_next_char", 10, -2,
+	"reading_punc_inc", 69, -2,
+	"rate_inc", 75, -2,
+	"key_backspace", 14, -1,
+	"bottom_edge", 18, -2,
+	"key_kp0", 82, -1,
+	"key_delete", 111, -1,
+	"key_prog1", 148, -1,
+	"say_char_num", 33, -2,
+	"key_kp1", 79, -1,
+	"key_end", 107, -1,
+	"key_prog2", 149, -1,
+	"key_kp2", 80, -1,
+	"say_prev_word", 12, -2,
+	"left_edge", 19, -2,
+	"key_kp3", 81, -1,
+	"key_katakanahiragana", 93, -1,
+	"key_right", 106, -1,
+	"key_kp4", 75, -1,
+	"key_find", 136, -1,
+	"key_kp5", 76, -1,
+	"speakup_cut", 4, -2,
+	"key_kp6", 77, -1,
+	"key_kp7", 71, -1,
+	"spkup_max_func", 47, -2,
+	"key_kp8", 72, -1,
+	"key_deletefile", 146, -1,
+	"key_f10", 68, -1,
+	"key_kp9", 73, -1,
+	"key_f11", 87, -1,
+	"key_sendfile", 145, -1,
+	"say_word", 11, -2,
+	"edit_repeat", 38, -2,
+	"key_leftbrace", 26, -1,
+	"key_f12", 88, -1,
+	"say_prev_line", 15, -2,
+	"say_from_top", 29, -2,
+	"var_start", 64, -2,
+	"reading_punc_dec", 68, -2,
+	"rate_dec", 74, -2,
+	"key_backslash", 43, -1,
+	"edit_exnum", 39, -2,
+	"key_kpslash", 98, -1,
+	"key_pagedown", 109, -1,
+	"key_kpplusminus", 118, -1,
+	"key_stop", 128, -1,
+	"key_props", 130, -1,
+	"pitch_inc", 77, -2,
+	"key_semicolon", 39, -1,
+	"key_rightalt", 100, -1,
+	"key_pageup", 104, -1,
+	"key_kpplus", 78, -1,
+	"say_line", 14, -2,
+	"bleeps_inc", 73, -2,
+	"key_leftshift", 42, -1,
+	"key_kpminus", 74, -1,
+	"key_paste", 135, -1,
+	"spell_delay_inc", 65, -2,
+	"punc_level_inc", 67, -2,
+	"key_www", 150, -1,
+	"edit_delim", 37, -2,
+	"key_capslock", 58, -1,
+	"key_muhenkan", 94, -1,
+	"key_compose", 127, -1,
+	"spk_key", 128, -2,
+	"key_sysrq", 99, -1,
+	"key_apostrophe", 40, -1,
+	"key_left", 105, -1,
+	"key_power", 116, -1,
+	"key_menu", 139, -1,
+	"voice_inc", 85, -2,
+	"key_kpcomma", 121, -1,
+	"spell_word", 22, -2,
+	"enable_win", 42, -2,
+	"key_a", 30, -1,
+	"key_henkan", 92, -1,
+	"key_bookmarks", 156, -1,
+	"say_line_indent", 28, -2,
+	"key_b", 48, -1,
+	"key_space", 57, -1,
+	"key_c", 46, -1,
+	"edit_some", 34, -2,
+	"key_d", 32, -1,
+	"key_numlock", 69, -1,
+	"key_home", 102, -1,
+	"shift", 1, -3,
+	"key_e", 18, -1,
+	"key_msdos", 151, -1,
+	"say_position", 24, -2,
+	"pitch_dec", 76, -2,
+	"key_f", 33, -1,
+	"key_cyclewindows", 154, -1,
+	"speakup_help", 45, -2,
+	"first_edit_bits", 34, -2,
+	"alt", 8, -3,
+	"key_g", 34, -1,
+	"key_kpenter", 96, -1,
+	"key_macro", 112, -1,
+	"bleeps_dec", 72, -2,
+	"ctrl", 4, -3,
+	"key_h", 35, -1,
+	"key_direction", 153, -1,
+	"key_i", 23, -1,
+	"spk_lock", 44, -2,
+	"spell_delay_dec", 64, -2,
+	"punc_level_dec", 66, -2,
+	"key_j", 36, -1,
+	"say_prev_char", 9, -2,
+	"key_k", 37, -1,
+	"key_102nd", 86, -1,
+	"key_l", 38, -1,
+	"key_ro", 89, -1,
+	"key_rightmeta", 126, -1,
+	"key_m", 50, -1,
+	"key_kpequal", 117, -1,
+	"key_undo", 131, -1,
+	"speech_kill", 2, -2,
+	"key_n", 49, -1,
+	"key_front", 132, -1,
+	"key_o", 24, -1,
+	"key_open", 134, -1,
+	"voice_dec", 84, -2,
+	"spk", 16, -3,
+	"key_p", 25, -1,
+	"say_last_char", 7, -2,
+	"say_from_left", 31, -2,
+	"key_q", 16, -1,
+	"key_slash", 53, -1,
+	"say_win", 43, -2,
+	"key_r", 19, -1,
+	"key_dot", 52, -1,
+	"say_char", 8, -2,
+	"vol_inc", 79, -2,
+	".", 0, 0
+};
diff -puN /dev/null drivers/char/speakup/mod_code.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/mod_code.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,25 @@
+/* this code is to modularize a synth specific file, included at the end */
+
+static void __exit mod_synth_exit( void )
+{
+        if ( synth == &MY_SYNTH )
+	  synth_release( );
+	synth_remove( &MY_SYNTH );
+}
+
+static int __init mod_synth_init( void )
+{
+	int status = do_synth_init( &MY_SYNTH );
+	if ( status != 0 ) return status;
+	synth_add( &MY_SYNTH );
+#if (LINUX_VERSION_CODE < 132419)
+//          MOD_INC_USE_COUNT;
+#endif
+	return 0;
+}
+
+module_init( mod_synth_init );
+module_exit( mod_synth_exit );
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_DESCRIPTION("Synthesizer driver module for speakup for the  synth->long_name");
+MODULE_LICENSE( "GPL" );
diff -puN /dev/null drivers/char/speakup/serialio.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/serialio.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,18 @@
+#ifndef SSPK_SERIAL
+#define SSPK_SERIAL
+
+#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 */
+#include <asm/serial.h>
+
+#define SPK_SERIAL_TIMEOUT 1000000	/* countdown values for serial timeouts */
+#define SPK_XMITR_TIMEOUT 1000000	/* countdown values transmitter/dsr timeouts */
+#define SPK_LO_TTY 0		/* check ttyS0 ... ttyS3 */
+#define SPK_HI_TTY 3
+#define NUM_DISABLE_TIMEOUTS 3	/* # of timeouts permitted before disable */
+#define SPK_TIMEOUT 100			/* buffer timeout in ms */
+#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
+
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_acnt.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_acnt.h	2005-09-07 19:39:50.000000000 -0700
@@ -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 */
diff -puN /dev/null drivers/char/speakup/speakup_acntpc.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_acntpc.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,160 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "speakup_acnt.h" /* local header file for Accent values */
+
+#define MY_SYNTH synth_acntpc
+#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( synth_port_tts ) == 'F' )
+#define PROCSPEECH '\r'
+
+
+static int synth_port_control;
+static unsigned int synth_portlist[] =
+    { 0x2a8, 0 };
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while (  (  ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+		if ( synth_full( ) )
+			return buf;
+		while ( synth_writable( ) );
+		outb_p( ch, synth_port_tts );
+	buf++;
+	}
+	return 0;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	synth_stop_timer( );
+	while (  synth_buff_out < synth_buff_in ) {
+		if ( synth_full( ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		while ( synth_writable( ) );
+		ch = *synth_buff_out++;
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+		outb_p( ch, synth_port_tts );
+		if ( jiffies >= jiff_max && ch == SPACE ) {
+			while ( synth_writable( ) );
+			outb_p( PROCSPEECH, synth_port_tts );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	while ( synth_writable( ) );
+	outb_p( PROCSPEECH, synth_port_tts );
+	synth_done(  );
+}
+
+static void synth_flush( void )
+{
+	outb_p( SYNTH_CLEAR, synth_port_tts );
+}
+
+static int synth_probe( void )
+{
+	unsigned int port_val = 0;
+	int i = 0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	if ( synth_port_forced ) {
+		synth_port_tts = synth_port_forced;
+		pr_info( "probe forced to %x by kernel command line\n", synth_port_tts );
+		if ( synth_request_region( synth_port_tts-1, SYNTH_IO_EXTENT ) ) {
+			pr_warn( "sorry, port already reserved\n" );
+			return -EBUSY;
+		}
+		port_val = inw( synth_port_tts-1 );
+		synth_port_control = synth_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] );
+			if ( ( port_val &= 0xfffc ) == 0x53fc ) { /* 'S' and out&input bits */
+				synth_port_control = synth_portlist[i];
+				synth_port_tts = synth_port_control+1;
+				break;
+			}
+		}
+	}
+	if ( ( port_val &= 0xfffc ) != 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 );
+	return 0;
+}
+
+static void accent_release(  void )
+{
+	if (  synth_port_tts )
+		synth_release_region( synth_port_tts-1, SYNTH_IO_EXTENT );
+	synth_port_tts = 0;
+}
+
+static int synth_is_alive( void )
+{
+	synth_alive = 1;
+	return 1;
+}
+
+static const char init_string[] = "\033=X \033Oi\033T2\033=M\033N1\n";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\033P8" },
+	{ CAPS_STOP, "\033P5" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" },
+	{ PITCH, "\033P%d", 5, 0, 9, 0, 0, 0 },
+	{ VOL, "\033A%d", 5, 0, 9, 0, 0, 0 },
+	{ TONE, "\033V%d", 5, 0, 9, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_acntpc = {"acntpc", "1.1", "Accent PC",
+	 init_string, 500, 50, 50, 1000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, accent_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL };
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_acntsa.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_acntsa.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,184 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+#include "speakup_acnt.h"	/* local header file for Accent values */
+
+#define MY_SYNTH synth_acntsa
+#define synth_full( ) ( inb_p( synth_port_tts ) == 'F' )
+#define PROCSPEECH '\r'
+
+static int timeouts = 0;	/* sequential number of timeouts */
+
+static int
+wait_for_xmitr ( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		return 0;
+	}
+	do { /* holding register empty? */
+		check = inb_p ( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn ( "%s:  timed out\n", synth->long_name );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do { /* CTS */
+		check = inb_p ( synth_port_tts + UART_MSR );
+		if ( --tmout == 0 ) {
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int
+spk_serial_out ( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr ( ) ) {
+		outb_p ( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static void
+do_catch_up ( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	synth_stop_timer ( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+	if ( ch == 0x0a ) ch = 0x0D;
+		if ( !spk_serial_out ( ch ) ) {
+			synth_delay ( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && ch == ' ' ) {
+			spk_serial_out ( PROCSPEECH );
+			synth_delay ( synth_delay_time );
+			return;
+		}
+	}
+	spk_serial_out ( PROCSPEECH );
+	synth_done( );
+}
+
+static char *synth_immediate ( char *buff )
+{
+	u_char ch;
+	while ( ( ch = *buff ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buff;
+	buff++;
+	}
+	return 0;
+}
+
+static void synth_flush ( void )
+{
+	spk_serial_out ( SYNTH_CLEAR );
+}
+
+static int serprobe ( int index )
+{
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	outb ( 0x0d, ser->port );
+	//	mdelay ( 1 );
+	/* ignore any error results, if port was forced */
+	if ( synth_port_forced ) return 0;
+	/* check for accent s.a now... */
+	if ( !synth_immediate( "\x18" ) )
+		return 0;
+	spk_serial_release( );
+	timeouts = synth_alive = 0;	/* not ignoring */
+	return -1;
+}
+
+static int synth_probe ( void )
+{
+	int i = 0, failed=0;
+	pr_info ( "Probing for %s.\n", synth->long_name );
+	for ( i = SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+        }
+        if ( failed ) {
+		pr_info ( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info ( "%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
+		synth_port_tts, synth_port_tts + 7, synth->version );
+	synth_immediate( "\033=R\r" );
+	mdelay( 100 );
+	return 0;
+}
+
+static int
+synth_is_alive ( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr ( ) > 0 ) {	/* restart */
+		synth_alive = 1;
+		synth_write_string ( synth->init );
+		return 2;
+	}
+	pr_warn ( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "\033T2\033=M\033Oi\033N1\n";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\033P8" },
+	{ CAPS_STOP, "\033P5" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\033R%c", 9, 0, 17, 0, 0, "0123456789abcdefgh" },
+	{ PITCH, "\033P%d", 5, 0, 9, 0, 0, 0 },
+	{ VOL, "\033A%d", 9, 0, 9, 0, 0, 0 },
+	{ TONE, "\033V%d", 5, 0, 9, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_acntsa = { "acntsa", "1.1", "Accent-SA",
+	init_string, 400, 5, 30, 1000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_apollo.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_apollo.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,195 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_apollo
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static int timeouts = 0;	/* sequential number of timeouts */
+
+static int wait_for_xmitr( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do {
+		check = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn( "APOLLO:  timed out\n" );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do {
+		check = inb( synth_port_tts + UART_MSR );
+				if ( --tmout == 0 ) {
+					timeouts++;
+					return 0;
+				}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out( const char ch )
+{
+ // int timer = 9000000;
+	if ( synth_alive && wait_for_xmitr( ) ) {
+		outb( ch, synth_port_tts );
+		/*while ( inb( synth_port_tts+UART_MSR ) & UART_MSR_CTS ) if ( --timer == 0 ) break;*/
+		/*    outb( UART_MCR_DTR, synth_port_tts + UART_MCR );*/
+		return 1;
+	}
+	return 0;
+}
+
+/*
+static unsigned char spk_serial_in( void )
+{
+	int c, lsr, tmout = SPK_SERIAL_TIMEOUT;
+	do {
+		lsr = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) return 0xff;
+	} while ( !( lsr & UART_LSR_DR ) );
+	c = inb( synth_port_tts + UART_RX );
+	return ( unsigned char ) c;
+}
+*/
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( !spk_serial_out( ch ) ) {
+			outb( UART_MCR_DTR, synth_port_tts + UART_MCR );
+			outb( UART_MCR_DTR | UART_MCR_RTS, synth_port_tts + UART_MCR );
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && synth_buff_out-synth_buffer > 10 ) {
+		spk_serial_out( PROCSPEECH );
+		synth_delay( synth_delay_time );
+		return;
+		}
+	}
+	spk_serial_out( PROCSPEECH );
+	synth_done( );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+	  outb( ch, synth_port_tts );
+	else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush ( void )
+{
+	spk_serial_out ( SYNTH_CLEAR );
+}
+
+static int serprobe( int index )
+{
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	outb( 0x0d, ser->port ); /* wake it up if older BIOS */
+	mdelay( 1 );
+	synth_port_tts = ser->port;
+	if ( synth_port_forced ) return 0;
+	/* check for apollo now... */
+	if ( !synth_immediate( "\x18" ) ) return 0;
+	pr_warn( "port %x failed\n", synth_port_tts );
+	spk_serial_release( );
+	timeouts = synth_alive = synth_port_tts = 0;
+	return -1;
+}
+
+static int synth_probe( void )
+{
+int i, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+	}
+	if ( failed ) {
+		pr_info( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info( "%s:  %03x-%03x, Driver version %s,\n", synth->long_name,
+	 synth_port_tts, synth_port_tts + 7, synth->version );
+	return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;  /* reenabled */
+	} else pr_warn( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "@R3@D0@K1\r";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "cap, " },
+	{ CAPS_STOP, "" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "@W%d", 6, 1, 9, 0, 0, 0 },
+	{ PITCH, "@F%x", 10, 0, 15, 0, 0, 0 },
+	{ VOL, "@A%x", 10, 0, 15, 0, 0, 0 },
+	{ VOICE, "@V%d", 1, 1, 6, 0, 0, 0 },
+	{ LANG, "@=%d,", 1, 1, 4, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_apollo = {"apollo", "1.2", "Apollo",
+	init_string, 500, 50, 50, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_audptr.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_audptr.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,201 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_audptr
+#define SYNTH_CLEAR 0x18 /* flush synth buffer */
+#define PROCSPEECH '\r' /* start synth processing speech char */
+
+static int timeouts = 0;	/* sequential number of timeouts */
+
+static int wait_for_xmitr( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do { /* holding register empty? */
+		check = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn( "%s:  timed out\n", synth->long_name );
+		  timeouts++;
+		  return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do { /* CTS */
+		check = inb( synth_port_tts + UART_MSR );
+		if ( --tmout == 0 ) {
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr( ) ) {
+		outb( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static unsigned char spk_serial_in( void )
+{
+	int c, lsr, tmout = SPK_SERIAL_TIMEOUT;
+	do {
+		lsr = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) return 0xff;
+	} while ( !( lsr & UART_LSR_DR ) );
+	c = inb( synth_port_tts + UART_RX );
+	return ( unsigned char ) c;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == 0x0a ) ch = PROCSPEECH;
+		if ( !spk_serial_out( ch ) ) {
+		  	synth_delay( synth_full_time );
+		  	return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && ch == SPACE ) {
+		  	spk_serial_out( PROCSPEECH );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	spk_serial_out( PROCSPEECH );
+	synth_done( );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush( void )
+{
+	while ( ( inb( synth_port_tts + UART_LSR ) & BOTH_EMPTY ) != BOTH_EMPTY );
+	outb( SYNTH_CLEAR, synth_port_tts );
+		  spk_serial_out( PROCSPEECH );
+		}
+
+static char synth_id[40] = "";
+
+static int serprobe( int index )
+{
+	u_char test = 0;
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	/* ignore any error results, if port was forced */
+	if ( synth_port_forced )
+		return 0;
+	synth_immediate( "\x05[Q]" );
+	if ( ( synth_id[test] = spk_serial_in( ) ) == '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 ( test != 32 )
+		  return 0;
+	}
+	spk_serial_release( );
+		    timeouts = synth_alive = 0; /* not ignoring */
+		    return -1;
+}
+
+static int synth_probe( void )
+{
+int i=0, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+	}
+	if ( failed ) {
+		pr_info( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info( "%s:  %03x-%03x, Driver %s,\n", synth->long_name,
+	 synth_port_tts, synth_port_tts + 7, synth->version );
+	if ( synth_id[0] == 'A' )
+	  pr_info( "%s version: %s", synth->long_name, synth_id );
+		return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;
+	}
+	return 0;
+}
+
+static const char init_string[] = "\x05[D1]\x05[Ol]";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x05[f99]" },
+	{ CAPS_STOP, "\x05[f80]" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x05[r%d]", 10, 0, 20, -100, 10, 0 },
+	{ PITCH, "\x05[f%d]", 80, 39, 4500, 0, 0, 0 },
+	{ VOL, "\x05[g%d]", 21, 0, 40, 0, 0, 0 },
+	{ TONE, "\x05[s%d]", 9, 0,63, 0, 0, 0 },
+	{ PUNCT, "\x05[A%c]", 0, 0, 3, 0, 0, "nmsa" },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_audptr = {"audptr", "1.1", "Audapter",
+	 init_string, 400, 5, 30, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_bns.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_bns.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,174 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_bns
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static int wait_for_xmitr( void )
+{
+	static int timeouts = 0;	/* sequential number of timeouts */
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do {
+		check = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+		 	pr_warn( "BNS:  timed out\n" );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do {
+		check = inb( synth_port_tts + UART_MSR );
+		if ( --tmout == 0 ) {
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr( ) ) {
+		outb( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == '\n' ) ch = PROCSPEECH;
+		if ( !spk_serial_out( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && ch == ' ' ) {
+			spk_serial_out( PROCSPEECH );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	spk_serial_out( PROCSPEECH );
+	synth_done( );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush ( void )
+{
+	spk_serial_out ( SYNTH_CLEAR );
+}
+
+static int serprobe( int index )
+{
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	outb( '\r', ser->port );
+	if ( synth_port_forced ) return 0;
+	/* check for bns now... */
+	if ( !synth_immediate( "\x18" ) ) return 0;
+	spk_serial_release( );
+	synth_alive = 0;
+				return -1;
+}
+
+static int synth_probe( void )
+{
+int i=0, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+        }
+        if ( failed ) {
+		pr_info( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info( "%s:  %03x-%03x, Driver version %s,\n", synth->long_name,
+		synth_port_tts, synth_port_tts + 7, synth->version );
+	return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;
+	}
+	pr_warn( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "\x05Z\x05\x43";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x05\x31\x32P" },
+	{ CAPS_STOP, "\x05\x38P" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x05%dE", 8, 1, 16, 0, 0, 0 },
+	{ PITCH, "\x05%dP", 8, 0, 16, 0, 0, 0 },
+	{ VOL, "\x05%dV", 8, 0, 16, 0, 0, 0 },
+	{ TONE, "\x05%dT", 8, 0, 16, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_bns = {"bns", "1.1", "Braille 'N Speak",
+	init_string, 500, 50, 50, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,2281 @@
+/* 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
+*/
+
+#define __KERNEL_SYSCALLS__
+
+#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>
+#if (LINUX_VERSION_CODE < 132419)
+#include <linux/console_struct.h>
+#include <linux/kbd_ll.h>
+#include <asm/keyboard.h>
+#endif
+#include <linux/ctype.h>
+#include <linux/selection.h>
+#include <asm/uaccess.h> /* copy_from|to|user( ) and others */
+#include <linux/unistd.h>
+
+#include <linux/keyboard.h>	/* for KT_SHIFT */
+#include <linux/kbd_kern.h> /* for vc_kbd_* and friends */
+#include <linux/vt_kern.h>
+#include <linux/input.h>
+#include <linux/kmod.h>
+#include <linux/speakup.h>
+
+#include "cvsversion.h"
+#include "spk_priv.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 <asm/uaccess.h>
+#include <linux/consolemap.h>
+
+#ifndef MIN
+#define MIN(a,b)        ((a) < (b) ? (a) : (b))
+#endif
+
+#define SPEAKUP_VERSION "Speakup v-2.00" CVSVERSION
+#define MAX_DELAY ( (500 * HZ ) / 1000 )
+#define KEY_MAP_VER 119
+#define MINECHOCHAR SPACE
+
+/* these are globals from the kernel code */
+extern void *kmalloc (size_t, unsigned int );
+extern void kfree (const void * );
+extern struct kbd_struct * kbd;
+extern int fg_console;
+extern short punc_masks[];
+
+static special_func special_handler = NULL;
+special_func help_handler = NULL;
+
+static int errno;
+int synth_file_inuse = 0;
+short pitch_shift = 0, synth_flags = 0;
+static char buf[256];
+short attrib_bleep = 0, bleeps = 0,  bleep_time = 1;
+short no_intr = 0, spell_delay = 0;
+short key_echo = 0, cursor_timeout = 120, say_word_ctl = 0;
+short say_ctrl = 0, bell_pos = 0;
+short punc_mask = 0, punc_level = 0, reading_punc = 0;
+char str_caps_start[MAXVARLEN+1] = "\0", str_caps_stop[MAXVARLEN+1] = "\0";
+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 }
+};
+char mark_cut_flag = 0;
+u_short mark_x = 0, mark_y = 0;
+static char synth_name[10] = CONFIG_SPEAKUP_DEFAULT;
+#define MAX_KEY 160
+u_char *our_keys[MAX_KEY], *shift_table;
+static u_char key_buf[600];
+static u_char key_defaults[] = {
+#include "speakupmap.h"
+};
+
+#if (LINUX_VERSION_CODE < 132419)
+extern struct tty_struct *tty;
+typedef void (*k_handler_fn)(unsigned char value, char up_flag);
+#define KBD_PROTO u_char value, char up_flag
+#define KBD_ARGS value, up_flag
+#else
+struct tty_struct *tty;
+#define key_handler k_handler
+typedef void (*k_handler_fn)(struct vc_data *vc, unsigned char value,
+                            char up_flag, struct pt_regs *regs);
+#define KBD_PROTO struct vc_data *vc, u_char value, char up_flag, struct pt_regs *regs
+#define KBD_ARGS vc, value, up_flag, regs
+#endif
+extern k_handler_fn key_handler[16];
+static k_handler_fn do_shift, do_spec, do_latin, do_cursor;
+EXPORT_SYMBOL( help_handler );
+EXPORT_SYMBOL( special_handler );
+EXPORT_SYMBOL( our_keys );
+
+static void speakup_date (struct vc_data *vc );
+static void spkup_write (const char *in_buf, int count );
+int set_mask_bits( const char *input, const int which, const int how );
+
+char str_ctl[] = "control-";
+char *colors[] = {
+	"black", "blue", "green", "cyan", "red", "magenta", "yellow", "white",
+	"grey"
+};
+
+char *phonetic[] = {
+	"alpha", "beta", "charley", "delta", "echo", "fox", "gamma", "hotel",
+	"india", "juleiet", "keelo", "leema", "mike", "november", "oscar",
+	"papa",
+	"quebec", "romeo", "seeara", "tango", "uniform", "victer", "wiskey",
+	"x ray", "yankee", "zooloo"
+};
+
+// array of 256 char pointers (one for each ASCII character description )
+// initialized to default_chars and user selectable via /proc/speakup/characters
+char *characters[256];
+
+char *default_chars[256] = {
+	"null", "^a", "^b", "^c", "^d", "^e", "^f", "^g",
+	"^h", "^i", "^j", "^k", "^l", "^m", "^n", "^o",
+	"^p", "^q", "^r", "^s", "^t", "^u", "^v", "^w",
+	"^x", "^y", "^z", NULL, NULL, NULL, NULL, NULL,
+	"space", "bang!", "quote", "number", "dollar", "percent", "and",
+	"tick",
+	"left paren", "right paren", "star", "plus", "comma", "dash", "dot",
+	"slash",
+	"zero", "one", "two", "three", "four", "five", "six", "seven",
+	"eight", "nine",
+	"colon", "semmy", "less", "equals", "greater", "question", "at",
+	"eigh", "b", "c", "d", "e", "f", "g",
+	"h", "i", "j", "k", "l", "m", "n", "o",
+	"p", "q", "r", "s", "t", "u", "v", "w", "x",
+	"y", "zehd", "left bracket", "backslash", "right bracket", "caret",
+	"line",
+	"accent", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, "left brace", "bar", "right brace", "tihlduh",
+	"delta", "see cedilla", "u oomlout", "e acute", /* 128 */
+	"eigh circumflex", "eigh oomlout", "eigh grave", "eigh ring", /* 132 */
+	"see cedilla", "e circumflex", "e oomlout", "e grave", /* 136 */
+	"i oomlout", "i circumflex", "i grave", "eigh oomlout", /* 140 */
+	"eigh ring", "e acute", "eigh e dipthong", "eigh e dipthong", /* 144 */
+	"o circumflex", "o oomlout", "o grave", "u circumflex", /* 148 */
+	"u grave", "y oomlout", "o oomlout", "u oomlout", /* 152 */
+	"cents", "pounds", "yen", "peseta", /* 156 */
+	"florin", "eigh acute", "i acute", "o acute", /* 160 */
+	"u acute", "n tilde", "n tilde", "feminine ordinal", /* 164 */
+	"masculin ordinal", "inverted question", "reversed not", "not", /* 168 */
+	"half", "quarter", "inverted bang", "much less than", /* 172 */
+	"much greater than", "dark shading", "medium shading", /* 176 */
+	"light shading", "verticle line", "left tee", /* 179 */
+	"double left tee", "left double tee", "double top right", /* 182 */
+	"top double right", "double left double tee", /* 185 */
+	"double vertical line", "double top double right", /* 187 */
+	"double bottom double right", "double bottom right", /* 189 */
+	"bottom double right", "top right", "left bottom", /* 191 */
+	"up tee", "tee down", "tee right", "horizontal line", /* 194 */
+	"cross bars", "tee double right", "double tee right", /* 198 */
+	"double left double bottom", "double left double top", /* 201 */
+	"double up double tee", "double tee double down", /* 203 */
+	"double tee double right", "double horizontal line", /* 205 */
+	"double cross bars", "up double tee", "double up tee", /* 207 */
+	"double tee down", "tee double down", /* 210 */
+	"double left bottom", "left double bottom", /* 212 */
+	"double left top", "left double top", /* 214 */
+	"double vertical cross", "double horizontal cross", /* 216 */
+	"bottom right", "left top", "solid square", /* 218 */
+	"solid lower half", "solid left half", "solid right half", /* 221 */
+	"solid upper half", "alpha", "beta", "gamma", /* 224 */
+	"pie", "sigma", "sigma", "mu", /* 228 */
+	"tou", "phigh", "thayta", "ohmega", /* 232 */
+	"delta", "infinity", "phigh", "epsilaun", /* 236 */
+"intersection", "identical to", "plus or minus", "equal grater than", /* 240 */
+	"less than equal", "upper integral", "lower integral", /* 244 */
+		"divided by", "almost equal", "degrees", /* 247 */
+	"centre dot", "bullet", "square root", /* 250 */
+	"power", "squared", "black square", "white space" /* 252 */
+};
+
+u_short spk_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 */
+B_SYM, 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 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 192-199 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 200-207 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 208-215 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 216-223 */
+B_SYM, B_SYM, B_SYM, B_CAPSYM, B_SYM, B_CAPSYM, B_SYM, B_SYM, /* 224-231 */
+B_SYM, B_CAPSYM, B_CAPSYM, B_CAPSYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 232-239 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, /* 240-247 */
+B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM, B_SYM /* 248-255 */
+};
+
+int spk_keydown = 0;
+static u_char spk_lastkey = 0, spk_close_press = 0, keymap_flags = 0;
+static u_char last_keycode = 0, this_speakup_key = 0;
+static u_long last_spk_jiffy = 0;
+
+spk_t *speakup_console[MAX_NR_CONSOLES];
+
+int spk_setup (char *str )
+{
+	int ints[4];
+	str = get_options (str, ARRAY_SIZE (ints ), ints );
+	if (ints[0] > 0 && ints[1] >= 0 )
+		synth_port_forced = ints[1];
+	return 1;
+}
+
+int spk_ser_setup (char *str )
+{
+	int lookup[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+	int ints[4];
+	str = get_options (str, ARRAY_SIZE (ints ), ints );
+	if (ints[0] > 0 && ints[1] >= 0 )
+		synth_port_forced = lookup[ints[1]];
+	return 1;
+}
+
+int spk_synth_setup (char *str )
+{
+	size_t len = MIN (strlen (str ), 9 );
+	memcpy (synth_name, str, len );
+	synth_name[len] = '\0';
+	return 1;
+}
+
+__setup ("speakup_port=", spk_setup );
+__setup ("speakup_ser=", spk_ser_setup );
+__setup ("speakup_synth=", spk_synth_setup );
+
+char *
+strlwr (char *s )
+{
+	char *p;
+	for (p = s; *p; p++ ) {
+		if (*p >= CAP_A && *p <= CAP_Z ) *p |= 32;
+	}
+	return s;
+}
+
+static void
+bleep (u_short val )
+{
+	static 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, time );
+}
+
+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 ) return;
+	do_flush( );
+}
+
+void
+speech_kill (struct vc_data *vc )
+{
+	char val = synth->is_alive ( );
+	if (val == 0 ) return;
+	/* re-enables synth, if disabled */
+	if (val == 2 || spk_killed ) {	/* dead */
+		spk_shut_up &= ~0x40;
+		synth_write_msg ("Eyem a Lighve!" );
+	} else {
+		synth_write_msg ("You killed speak up!" );
+		spk_shut_up |= 0x40;
+	}
+}
+
+static void
+speakup_off (struct vc_data *vc )
+{
+	if (spk_shut_up & 0x80 ) {
+		spk_shut_up &= 0x7f;
+		synth_write_msg ("hey. That's better!" );
+	} else {
+		spk_shut_up |= 0x80;
+		synth_write_msg ("You turned me off!" );
+	}
+	speakup_date (vc );
+}
+
+static void
+speakup_parked (struct vc_data *vc )
+{
+	if (spk_parked & 0x80 ) {
+		spk_parked = 0;
+		synth_write_msg ("unparked!" );
+	} else {
+		spk_parked |= 0x80;
+		synth_write_msg ("parked!" );
+	}
+}
+
+/* ------ cut and paste ----- */
+/* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */
+#undef isspace
+#define isspace(c)      ((c) == ' ')
+/* Variables for selection control. */
+struct vc_data *spk_sel_cons;      /* defined in selection.c must not be disallocated */
+static volatile int sel_start = -1;     /* cleared by clear_selection */
+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));
+}
+
+static void
+speakup_clear_selection(void)
+{
+	sel_start = -1;
+}
+
+/* does screen address p correspond to character at LH/RH edge of screen? */
+static inline int atedge(const int p, int size_row)
+{
+	return (!(p % size_row) || !((p + 2) % size_row));
+}
+
+/* constrain v such that v <= u */
+static inline unsigned short limit(const unsigned short v, const unsigned short u)
+{
+        return (v > u) ? u : v;
+}
+
+unsigned short xs, ys, xe, ye; /* our region points */
+
+static 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) &&
+	    isspace(sel_pos(new_sel_end))) {
+		for (pe = new_sel_end + 2; ; pe += 2)
+			if (!isspace(sel_pos(pe)) ||
+			    atedge(pe, vc->vc_size_row))
+				break;
+		if (isspace(sel_pos(pe)))
+			new_sel_end = pe;
+        }
+	if ((new_sel_start == sel_start)
+	    && (new_sel_end == sel_end))     /* no action required */
+	      return 0;
+
+        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;
+        }
+        if (sel_buffer)
+		kfree(sel_buffer);
+        sel_buffer = bp;
+
+        obp = bp;
+        for (i = sel_start; i <= sel_end; i += 2) {
+		*bp = sel_pos(i);
+		if (!isspace(*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;
+}
+
+static 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)) {
+      schedule();
+      continue;
+    }
+    count = sel_buffer_lth - pasted;
+    count = MIN(count, tty->ldisc.receive_room(tty));
+    tty->ldisc.receive_buf(tty, sel_buffer + pasted, 0, count);
+    pasted += count;
+  }
+  remove_wait_queue(&vc->paste_wait, &wait);
+  current->state = TASK_RUNNING;
+  return 0;
+}
+
+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 = spk_x;
+		ys = spk_y;
+		spk_sel_cons = vc;
+		synth_write_msg ("mark" );
+		return;
+	}
+	xe = (u_short ) spk_x;
+	ye = (u_short )spk_y;
+	mark_cut_flag = 0;
+	synth_write_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_write_msg ("mark, cleared" );
+	} else {
+		synth_write_msg ("paste" );
+		speakup_paste_selection (tty );
+	}
+}
+
+static void
+say_attributes (struct vc_data *vc )
+{
+	int fg= spk_attr&0x0f, bg = spk_attr>>4;
+	if (fg > 8 ) {
+		synth_write_string("bright " );
+		fg -= 8;
+	}
+	synth_write_string(colors[fg] );
+	if (bg > 7 ) {
+		synth_write_string(" on blinking " );
+		bg -= 8;
+	} else
+		synth_write_string(" on " );
+	synth_write_msg(colors[bg] );
+}
+
+static char *blank_msg = "blank";
+static char *edges[] = { "top, ", "bottom, ", "left, ", "right, ", "" };
+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 )
+		synth_write_msg (edges[msg_id-1] );
+}
+
+static void
+speak_char( u_char ch )
+{
+	char *cp = characters[ ch];
+	synth_buffer_add( SPACE );
+	if (IS_CHAR(ch, B_CAP ) ) {
+		pitch_shift++;
+		synth_write_string(str_caps_start );
+		synth_write_string(cp );
+		synth_write_string(str_caps_stop );
+	} else {
+		if (*cp == '^' ) {
+			synth_write_string(str_ctl );
+			cp++;
+		}
+		synth_write_string(cp );
+	}
+	synth_buffer_add( SPACE );
+}
+
+static void
+say_char (struct vc_data *vc )
+{
+	u_short ch;
+	spk_old_attr = spk_attr;
+	ch = scr_readw ((u_short * ) spk_pos );
+	spk_attr = ((ch & 0xff00 ) >> 8 );
+	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 = scr_readw ((u_short * ) spk_pos );
+	spk_attr = ((ch & 0xff00 ) >> 8 );
+		if ( IS_CHAR(ch, B_ALPHA ) ) {
+		ch &= 0x1f;
+		synth_write_msg(phonetic[--ch] );
+	} else {
+		if ( IS_CHAR(ch, B_NUM ) )
+		synth_write_string( "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;
+	spk_old_attr = spk_attr;
+	ch = (char ) scr_readw ((u_short * ) tmp_pos );
+
+/* decided to take out the sayword if on a space (mis-information */
+	if ( say_word_ctl && ch == SPACE ) {
+		*buf = '\0';
+		synth_write_msg( "space" );
+		return 0;
+	} else if ((tmpx < vc->vc_cols-2 )
+		   && (ch == SPACE || IS_WDLM(ch ))
+		   && ((char) scr_readw ((u_short * ) tmp_pos+1 ) > SPACE)) {
+	  tmp_pos += 2;
+	  tmpx++;
+	} else
+	while (tmpx > 0 ) {
+	  if (((ch = (char ) scr_readw ((u_short * ) tmp_pos-1 )) == SPACE
+	       || IS_WDLM(ch ))
+	      && ((char) scr_readw ((u_short * ) tmp_pos ) > SPACE))
+	    break;
+	  tmp_pos -= 2;
+	  tmpx--;
+	}
+	attr_ch = scr_readw ((u_short * ) tmp_pos );
+	spk_attr = attr_ch >> 8;
+	buf[cnt++] = attr_ch&0xff;
+	while (tmpx < vc->vc_cols-1 ) {
+	  tmp_pos += 2;
+	  tmpx++;
+	  ch = (char ) scr_readw ((u_short * ) tmp_pos );
+	  if ((ch == SPACE )
+	      || (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 )
+{
+	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 ) scr_readw ((u_short * ) spk_pos );
+		if ( ch == SPACE ) 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 )
+{
+	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 ) scr_readw ((u_short * ) spk_pos );
+		if ( ch == SPACE ) 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_write_string (delay_str[spell_delay] );
+		if (IS_CHAR(ch, B_CAP ) ) {
+			str_cap = str_caps_start;
+			if ( *str_caps_stop ) pitch_shift++;
+		else last_cap = str_caps_stop; /* synth has no pitch */
+		} else str_cap = str_caps_stop;
+		if ( str_cap !=last_cap ) {
+			synth_write_string( str_cap );
+			last_cap = str_cap;
+		}
+		if ( this_speakup_key == SPELL_PHONETIC && ( IS_CHAR( ch, B_ALPHA ) ) ) {
+			ch &= 31;
+			cp1 = phonetic[--ch];
+		} else {
+			cp1 = characters[ch];
+			if (*cp1 == '^' ) {
+				synth_write_string(str_ctl );
+				cp1++;
+			}
+		}
+		synth_write_string(cp1 );
+	cp++;
+	}
+	if ( str_cap != str_caps_stop )
+		synth_write_string( str_caps_stop );
+}
+
+static int
+get_line (struct vc_data *vc )
+{
+	u_long tmp = spk_pos - (spk_x * 2 );
+	int i = 0;
+	spk_old_attr = spk_attr;
+	spk_attr = (u_char ) (scr_readw ((u_short * ) spk_pos ) >> 8 );
+	for (i = 0; i < vc->vc_cols; i++ ) {
+		buf[i] = (u_char ) scr_readw ((u_short * ) tmp );
+		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;
+	char num_buf[8];
+	u_short saved_punc_mask = punc_mask;
+	if (i == 0 ) {
+		synth_write_msg (blank_msg );
+		return;
+	}
+	buf[i++] = '\n';
+	if ( this_speakup_key == SAY_LINE_INDENT ) {
+		for ( cp = buf; *cp == SPACE; cp++ );
+		sprintf( num_buf, "%d, ", ( cp-buf )+1 );
+		synth_write_string( num_buf );
+	}
+	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_short saved_punc_mask = punc_mask;
+	spk_old_attr = spk_attr;
+	spk_attr = (u_char ) (scr_readw ((u_short * ) from ) >> 8 );
+	while (from < to ) {
+		buf[i++] = (char ) scr_readw ((u_short * ) from );
+		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 )
+		synth_write_msg (blank_msg );
+}
+
+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_write_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_write_msg( blank_msg );
+		return;
+	}
+	for ( i = 0; i < len; i++ ) if ( buf[i] != SPACE ) break;
+	ch = buf[i];
+	spk_pos -= ( spk_x-i ) * 2;
+	spk_x = i;
+	sprintf (buf, "%d, ", ++i );
+	synth_write_string (buf );
+	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_write_msg( blank_msg );
+		return;
+	}
+	ch = buf[--len];
+	spk_pos -= ( spk_x-len ) * 2;
+	spk_x = len;
+	sprintf (buf, "%d, ", ++len );
+	synth_write_string (buf );
+	speak_char( ch );
+}
+
+static void
+say_position (struct vc_data *vc )
+{
+	sprintf (buf, "line %ld, col %ld, t t y %d\n", spk_y + 1,
+		     spk_x + 1, vc->vc_num + 1 );
+	synth_write_string (buf );
+}
+
+// Added by brianb
+static void
+say_char_num (struct vc_data *vc )
+{
+	u_short ch = scr_readw ((u_short * ) spk_pos );
+	ch &= 0x0ff;
+	sprintf (buf, "hex %02x, decimal %d", ch, ch );
+	synth_write_msg (buf );
+}
+
+/* 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;
+	static u_char *exn_ptr = NULL;
+	int in_count = count;
+	char rpt_buf[32];
+	spk_keydown = 0;
+	while ( count-- ) {
+		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 ) {
+				sprintf (rpt_buf, " times %d . ", ++rep_count );
+				synth_write_string (rpt_buf );
+			}
+			rep_count = 0;
+		}
+		if ( !( char_type&B_NUM ) )
+				exn_ptr = NULL;
+		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_write( &ch, 1 );
+		} else if ( ( char_type&B_NUM ) ) {
+			rep_count = 0;
+			if ( (last_type&B_EXNUM) && synth_buff_in == exn_ptr+1 ) {
+				synth_buff_in--;
+				synth_buffer_add( old_ch );
+				exn_ptr = NULL;
+			}
+			synth_write( &ch, 1 );
+		} 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_write( &ch, 1 );
+			else rep_count = 0;
+		} else {
+			if ( ( char_type&B_EXNUM ) )
+					exn_ptr = (u_char *)synth_buff_in;
+/* 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) ) {
+			sprintf (rpt_buf, " repeated %d . ", ++rep_count );
+			synth_write_string (rpt_buf );
+		}
+		rep_count = 0;
+	}
+}
+
+static char *ctl_key_ids[] = {
+	"shift", "altgr", "control", "ault", "l shift", "speakup",
+"l control", "r control"
+};
+#define NUM_CTL_LABELS 8
+
+static void
+handle_shift( KBD_PROTO )
+{
+	(*do_shift)( KBD_ARGS );
+	if ( synth == NULL || up_flag || spk_killed ) return;
+	spk_shut_up &= 0xfe;
+	do_flush( );
+	if ( say_ctrl && value < NUM_CTL_LABELS )
+		synth_write_string ( ctl_key_ids[value] );
+}
+
+static void
+handle_latin( KBD_PROTO )
+{
+	(*do_latin)( KBD_ARGS );
+	if ( up_flag ) {
+		spk_lastkey = spk_keydown = 0;
+		return;
+	}
+	if ( synth == NULL || spk_killed ) return;
+	spk_shut_up &= 0xfe;
+	spk_lastkey = value;
+	spk_keydown++;
+	spk_parked &= 0xfe;
+	if ( key_echo == 2 && value >= MINECHOCHAR )
+		speak_char( value );
+}
+
+static int
+set_key_info( u_char *key_info, u_char *k_buffer )
+{
+	int i = 0,  states, key_data_len;
+	u_char *cp = key_info, *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;
+}
+
+num_var spk_num_vars[] = { /* bell must be first to set high limit */
+	{ BELL_POS, 0, 0, 0, 0, 0, 0, 0 },
+	{ SPELL_DELAY, 0, 0, 0, 5, 0, 0, 0 },
+	{ ATTRIB_BLEEP, 0, 1, 0, 3, 0, 0, 0 },
+	{ BLEEPS, 0, 3, 0, 3, 0, 0, 0 },
+	{ BLEEP_TIME, 0, 4, 1, 20, 0, 0, 0 },
+	{ PUNC_LEVEL, 0, 1, 0, 4, 0, 0, 0 },
+	{ READING_PUNC, 0, 1, 0, 4, 0, 0, 0 },
+	{ CURSOR_TIME, 0, 120, 50, 600, 0, 0, 0 },
+	{ SAY_CONTROL, TOGGLE_0 },
+	{ SAY_WORD_CTL, TOGGLE_0 },
+	{ NO_INTERRUPT, TOGGLE_0 },
+	{ KEY_ECHO, 0, 1, 0, 2, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+static int cursor_track = 1;
+static char *cursor_msgs[] = { "cursoring off", "cursoring on",
+	"attribute cursor" };
+#define MAXCURSORTRACK 1
+/* increase when we add more cursor modes */
+/* attribute cursor code coming soon */
+
+static void
+toggle_cursoring( struct vc_data *vc )
+{
+        cursor_track++;
+	if ( cursor_track > MAXCURSORTRACK )
+		cursor_track = 0;
+	synth_write_msg (cursor_msgs[cursor_track] );
+}
+
+static void
+reset_default_chars (void )
+{
+	int i;
+	if (default_chars[(int )'a'] == NULL ) { /* lowers are null first time */
+		for (i = (int )'a'; default_chars[i] == NULL; i++ )
+			default_chars[i] = default_chars[i-32];
+	} else { /* free any non-default */
+		for (i = 0; i < 256; i++ ) {
+			if (characters[i] != default_chars[i] )
+				kfree (characters[i] );
+		}
+	}
+		memcpy( characters, default_chars, sizeof( default_chars ) );
+}
+
+static void
+handle_cursor( KBD_PROTO );
+static void
+handle_spec( KBD_PROTO );
+static void
+cursor_done(u_long data );
+declare_timer( cursor_timer );
+
+void __init speakup_open (struct vc_data *vc, spk_t *first_console )
+{
+	int i;
+	num_var *n_var;
+	reset_default_chars ( );
+	memset( speakup_console, 0, sizeof( speakup_console ) );
+	if ( first_console == NULL ) return;
+	memset( first_console, 0, spk_size );
+	speakup_console[vc->vc_num] = first_console;
+	speakup_date( vc);
+	pr_info ("%s: initialized\n", SPEAKUP_VERSION );
+	init_timer (&cursor_timer );
+#if (LINUX_VERSION_CODE >= 132419)
+	cursor_timer.entry.prev=NULL;
+#endif
+	cursor_timer.function = cursor_done;
+	init_sleeper ( synth_sleeping_list );
+	strlwr (synth_name );
+	synth_init ( synth_name );
+ 	spk_num_vars[0].high = vc->vc_cols;
+	for ( n_var = spk_num_vars; n_var->var_id >= 0; n_var++ )
+		speakup_register_var( n_var );
+	for (i = 1; punc_info[i].mask != 0; i++ )
+		set_mask_bits( 0, i, 2 );
+	do_latin = key_handler[KT_LATIN];
+	key_handler[KT_LATIN] = handle_latin;
+	do_spec = key_handler[KT_SPEC];
+	key_handler[KT_SPEC] = handle_spec;
+	do_cursor = key_handler[KT_CUR];
+	key_handler[KT_CUR] = handle_cursor;
+	do_shift = key_handler[KT_SHIFT];
+	key_handler[KT_SHIFT] = handle_shift;
+	set_key_info( key_defaults, key_buf );
+}
+
+#ifdef CONFIG_PROC_FS
+
+// speakup /proc interface code
+
+/* Usage:
+cat /proc/speakup/version
+
+cat /proc/speakup/characters > foo
+less /proc/speakup/characters
+vi /proc/speakup/characters
+
+cat foo > /proc/speakup/characters
+cat > /proc/speakup/characters
+echo 39 apostrophe > /proc/speakup/characters
+echo 87 w > /proc/speakup/characters
+echo 119 w > /proc/speakup/characters
+echo defaults > /proc/speakup/characters
+echo reset > /proc/speakup/characters
+*/
+
+// keymap handlers
+
+static int
+keys_read_proc (PROC_READ_PROTOTYPE )
+{
+	char *cp = page;
+	int i, n, num_keys, nstates;
+	u_char *cp1 = key_buf + SHIFT_TBL_SIZE, ch;
+	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 );
+	*start = 0;
+	*eof = 1;
+	return (int)(cp-page);
+}
+
+static 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;
+}
+
+static int
+keys_write_proc (PROC_WRITE_PROTOTYPE )
+{
+	int i, ret = count;
+	char *in_buff, *cp;
+	u_char *cp1;
+	if (count < 1 || count > 1800 )
+		return -EINVAL;
+	in_buff = ( char * ) __get_free_page ( GFP_KERNEL );
+	if ( !in_buff ) return -ENOMEM;
+	if (copy_from_user (in_buff, buffer, count ) ) {
+		free_page ( ( unsigned long ) in_buff );
+		return -EFAULT;
+	}
+	if (in_buff[count - 1] == '\n' ) count--;
+	in_buff[count] = '\0';
+	if ( count == 1 && *in_buff == 'd' ) {
+		free_page ( ( unsigned long ) in_buff );
+		set_key_info( key_defaults, key_buf );
+		return ret;
+	}
+	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] );
+		free_page ( ( unsigned long ) in_buff );
+		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" );
+		}
+	}
+	free_page ( ( unsigned long ) in_buff );
+	return ret;
+}
+
+// this is the handler for /proc/speakup/version
+static int
+version_read_proc (PROC_READ_PROTOTYPE )
+{
+	int len = sprintf (page, "%s\n", SPEAKUP_VERSION );
+	if ( synth != NULL )
+		len += sprintf( page+len, "synth %s version %s\n",
+			synth->name, synth->version );
+	*start = 0;
+	*eof = 1;
+	return len;
+}
+
+// this is the read handler for /proc/speakup/characters
+static int
+chars_read_proc (PROC_READ_PROTOTYPE )
+{
+	int i, len = 0;
+	off_t begin = 0;
+	char *cp;
+	for (i = 0; i < 256; i++ ) {
+		cp = (characters[i] ) ? characters[i] : "NULL";
+		len += sprintf (page + len, "%d\t%s\n", i, cp );
+		if (len + begin > off + count )
+			break;
+		if (len + begin < off ) {
+			begin += len;
+			len = 0;
+		}
+	}
+	if (i >= 256 )
+		*eof = 1;
+	if (off >= len + begin )
+		return 0;
+	*start = page + (off - begin );
+	return ((count < begin + len - off ) ? count : begin + len - off );
+}
+
+static volatile int chars_timer_active = 0;	// indicates when timer is set
+static declare_timer( chars_timer );
+
+static inline void
+chars_stop_timer (void )
+{
+	if (chars_timer_active )
+		stop_timer ( chars_timer );
+}
+
+static int strings, rejects, updates;
+
+static void
+show_char_results (u_long data )
+{
+	int len;
+	char buf[80];
+	chars_stop_timer ( );
+	len = sprintf (buf, " updated %d of %d character descriptions\n",
+		       updates, strings );
+	if (rejects )
+		sprintf (buf + (len-1), " with %d reject%s\n",
+			 rejects, rejects > 1 ? "s" : "" );
+	printk( buf );
+}
+
+/* this is the write handler for /proc/speakup/silent */
+static int
+silent_write_proc (PROC_WRITE_PROTOTYPE )
+{
+	struct vc_data *vc = vc_cons[fg_console].d;
+	char ch = 0, shut;
+	if (count > 0 || count < 3 ) {
+		get_user (ch, buffer );
+		if ( ch == '\n' ) ch = '0';
+	}
+	if ( ch < '0' || ch > '7' ) {
+		pr_warn ( "silent value not in range (0,7)\n" );
+		return count;
+	}
+	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;
+	return count;
+}
+
+// this is the write handler for /proc/speakup/characters
+static int
+chars_write_proc (PROC_WRITE_PROTOTYPE )
+{
+#define max_desc_len 72
+	static int cnt = 0, state = 0;
+	static char desc[max_desc_len + 1];
+	static u_long jiff_last = 0;
+	short i = 0, num;
+	int len;
+	char ch, *cp, *p_new;
+	// reset certain vars if enough time has elapsed since last called
+	if (jiffies - jiff_last > 10 ) {
+		cnt = state = strings = rejects = updates = 0;
+	}
+	jiff_last = jiffies;
+get_more:
+	desc[cnt] = '\0';
+	state = 0;
+	for (; i < count && state < 2; i++ ) {
+		get_user (ch, buffer + i );
+		if ( ch == '\n' ) {
+			desc[cnt] = '\0';
+			state = 2;
+		} else if (cnt < max_desc_len )
+			desc[cnt++] = ch;
+	}
+	if (state < 2 ) return count;
+	cp = desc;
+	while ( *cp && *cp <= SPACE ) cp++;
+	if ((!cnt ) || strchr ("dDrR", *cp ) ) {
+		reset_default_chars ( );
+		pr_info( "character descriptions reset to defaults\n" );
+		cnt = 0;
+		return count;
+	}
+	cnt = 0;
+	if (*cp == '#' ) goto get_more;
+	num = -1;
+	cp = speakup_s2i(cp, &num );
+	while ( *cp && *cp <= SPACE ) cp++;
+	if (num < 0 || num > 255 ) {	// not in range
+		rejects++;
+		strings++;
+		goto get_more;
+	}
+	if (num >= 27 && num <= 31 ) goto get_more;
+	if (!strcmp(cp, characters[num] ) ) {
+		strings++;
+		goto get_more;
+	}
+	len = strlen(cp );
+	if (characters[num] == default_chars[num] )
+		p_new = (char * ) kmalloc (sizeof (char ) * len+1, GFP_KERNEL );
+	else if ( strlen(characters[num] ) >= len )
+		p_new = characters[num];
+	else {
+		kfree(characters[num] );
+		characters[num] = default_chars[num];
+		p_new = (char * ) kmalloc (sizeof (char ) * len+1, GFP_KERNEL );
+	}
+	if (!p_new ) return -ENOMEM;
+	strcpy ( p_new, cp );
+	characters[num] = p_new;
+	updates++;
+	strings++;
+	if (i < count ) goto get_more;
+	chars_stop_timer ( );
+	init_timer (&chars_timer );
+	chars_timer.function = show_char_results;
+	chars_timer.expires = jiffies + 5;
+		start_timer (chars_timer );
+	chars_timer_active++;
+	return count;
+}
+
+static int
+bits_read_proc (PROC_READ_PROTOTYPE )
+{
+	int i;
+	var_header *p_header = (var_header * )data;
+	proc_var *var = p_header->data;
+	bits_data *pb = &punc_info[var->value];
+	short mask = pb->mask;
+	char *cp = page;
+	*start = 0;
+	*eof = 1;
+	for ( i = 33; i < 128; i++ ) {
+		if ( !(spk_chartab[i]&mask ) ) continue;
+		*cp++ = (char )i;
+	}
+	*cp++ = '\n';
+	return cp-page;
+}
+
+/* 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;
+}
+
+static 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_write_msg( "edit done" );
+		special_handler = NULL;
+		return 1;
+	}
+	if ( mask < PUNC && !(ch_type&PUNC) ) return -1;
+	spk_chartab[ch] ^= mask;
+	speak_char( ch );
+	synth_write_msg( (spk_chartab[ch]&mask ) ? " on" : " off" );
+	return 1;
+}
+
+static int
+bits_write_proc (PROC_WRITE_PROTOTYPE )
+{
+	var_header *p_header = (var_header * )data;
+	proc_var *var = p_header->data;
+	int ret = count;
+	char punc_buf[100];
+	if (count < 1 || count > 99 )
+		return -EINVAL;
+	if (copy_from_user (punc_buf, buffer, count ) )
+		return -EFAULT;
+	if (punc_buf[count - 1] == '\n' )
+		count--;
+	punc_buf[count] = '\0';
+	if ( *punc_buf == 'd' || *punc_buf == 'r' )
+		count = set_mask_bits( 0, var->value, 3 );
+	else
+		count = set_mask_bits( punc_buf, var->value, 3 );
+	if ( count < 0 ) return count;
+	return ret;
+}
+
+// this is the read handler for /proc/speakup/synth
+static int
+synth_read_proc (PROC_READ_PROTOTYPE )
+{
+	int len;
+	if ( synth == NULL ) strcpy( synth_name, "none" );
+	else strcpy( synth_name, synth->name );
+	len = sprintf (page, "%s\n", synth_name );
+	*start = 0;
+	*eof = 1;
+	return len;
+}
+
+// this is the write handler for /proc/speakup/synth
+static int
+synth_write_proc (PROC_WRITE_PROTOTYPE )
+{
+	int ret = count;
+	char new_synth_name[10];
+	const char *old_name = ( synth != NULL ) ? synth->name : "none";
+	if (count < 2 || count > 9 )
+		return -EINVAL;
+	if (copy_from_user (new_synth_name, buffer, count ) )
+		return -EFAULT;
+	if (new_synth_name[count - 1] == '\n' )
+		count--;
+	new_synth_name[count] = '\0';
+	strlwr (new_synth_name );
+	if (!strcmp (new_synth_name, old_name ) ) {
+		pr_warn ( "%s already in use\n", new_synth_name );
+		return ret;
+	}
+	if ( synth_init( new_synth_name ) == 0 ) return ret;
+	pr_warn( "failed to init synth %s\n", new_synth_name );
+	return -ENODEV;
+}
+
+proc_var spk_proc_vars[] = {
+	 { VERSION, version_read_proc, 0, 0 },
+	 { SILENT, 0, silent_write_proc, 0 },
+	 { CHARS, chars_read_proc, chars_write_proc, 0 },
+	 { SYNTH, synth_read_proc, synth_write_proc, 0 },
+	 { KEYMAP, keys_read_proc, keys_write_proc, 0 },
+	 { PUNC_SOME, bits_read_proc, bits_write_proc, 1 },
+	 { PUNC_MOST, bits_read_proc, bits_write_proc, 2 },
+	 { PUNC_ALL, bits_read_proc, 0, 3 },
+	 { DELIM, bits_read_proc, bits_write_proc, 4 },
+	 { REPEATS, bits_read_proc, bits_write_proc, 5 },
+	 { EXNUMBER, bits_read_proc, bits_write_proc, 6 },
+	{ -1, 0, 0, 0 }
+};
+
+#endif // CONFIG_PROC_FS
+
+#ifdef CONFIG_SPEAKUP
+
+void __init
+speakup_init (struct vc_data *vc )
+{
+	spk_t *first_console = (spk_t *) alloc_bootmem (spk_size+1 );
+	speakup_open( vc, first_console );
+}
+
+#endif
+
+void
+speakup_allocate (struct vc_data *vc )
+{
+	int vc_num = vc->vc_num;
+	if ( speakup_console[vc_num] == NULL ) {
+		speakup_console[vc_num] = (spk_t *) kmalloc (spk_size + 1,
+			GFP_KERNEL );
+		if ( speakup_console[vc_num] == NULL ) return;
+		memset( speakup_console[vc_num], 0, spk_size );
+		speakup_date( vc);
+	} else if ( !spk_parked ) speakup_date( vc);
+}
+
+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 = ((scr_readw ((u_short * ) spk_pos ) & 0xff00 ) >> 8 );
+}
+
+static u_char is_cursor = 0;
+static u_long old_cursor_pos, old_cursor_x, old_cursor_y;
+static int cursor_con;
+volatile int cursor_timer_active = 0;
+
+void
+cursor_stop_timer(void )
+{
+  if (!cursor_timer_active ) return;
+		stop_timer ( cursor_timer );
+	cursor_timer_active = 0;
+}
+
+static void
+handle_cursor( KBD_PROTO )
+{
+	(*do_cursor)( KBD_ARGS );
+	spk_parked &= 0xfe;
+	if ( synth == NULL || up_flag || spk_shut_up || cursor_track == 0 )
+	  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;
+	cursor_con = vc->vc_num;
+	cursor_stop_timer( );
+	cursor_timer.expires = jiffies + cursor_timeout;
+		start_timer (cursor_timer );
+	cursor_timer_active++;
+}
+
+static void
+cursor_done (u_long data )
+{
+	struct vc_data *vc = vc_cons[cursor_con].d;
+	cursor_stop_timer( );
+	if (cursor_con != fg_console ) {
+		is_cursor = 0;
+		return;
+	}
+	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;
+			return;
+		}
+	}
+	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;
+}
+
+/* These functions are the interface to speakup from the actual kernel code. */
+
+void
+speakup_bs (struct vc_data *vc )
+{
+	if (!spk_parked )
+		speakup_date (vc );
+	if ( spk_shut_up || synth == NULL ) return;
+	if ( vc->vc_num == fg_console  && spk_keydown ) {
+		spk_keydown = 0;
+		if (!is_cursor ) say_char (vc );
+	}
+}
+
+void
+speakup_con_write (struct vc_data *vc, const char *str, int len )
+{
+	if (spk_shut_up || (vc->vc_num != fg_console ) )
+		return;
+	if (bell_pos && spk_keydown && (vc->vc_x == bell_pos - 1 ) )
+		bleep(3 );
+	if (synth == NULL || is_cursor ) 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 ) return;
+	}
+	spkup_write (str, len );
+}
+
+void
+speakup_con_update (struct vc_data *vc )
+{
+	if ( speakup_console[vc->vc_num] == NULL || spk_parked )
+		return;
+	speakup_date (vc );
+}
+
+static void
+handle_spec( KBD_PROTO )
+{
+	int on_off = 2;
+	char *label;
+static const char *lock_status[] = { " off", " on", "" };
+	(*do_spec)( KBD_ARGS );
+	if ( synth == NULL || up_flag || spk_killed ) return;
+	spk_shut_up &= 0xfe;
+	if ( no_intr ) do_flush( );
+	switch (value ) {
+		case KVAL( K_CAPS ):
+			label = "caps lock";
+			on_off =  (vc_kbd_led(kbd , VC_CAPSLOCK ) );
+			break;
+		case KVAL( K_NUM ):
+			label = "num lock";
+			on_off = (vc_kbd_led(kbd , VC_NUMLOCK ) );
+			break;
+		case KVAL( K_HOLD ):
+			label = "scroll lock";
+			on_off = (vc_kbd_led(kbd , VC_SCROLLOCK ) );
+			break;
+	default:
+		spk_parked &= 0xfe;
+		return;
+	}
+	synth_write_string ( label );
+	synth_write_msg ( lock_status[on_off] );
+}
+
+static int
+inc_dec_var( u_char value )
+{
+	var_header *p_header;
+	num_var *var_data;
+	char num_buf[32];
+	char *cp = num_buf, *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;
+		}
+	}
+	sprintf( cp, " %d ", (int)var_data->value );
+	synth_write_string( num_buf );
+	return 0;
+}
+
+static void
+speakup_win_set (struct vc_data *vc )
+{
+	char info[40];
+	if ( win_start > 1 ) {
+		synth_write_msg( "window already set, clear then reset" );
+		return;
+	}
+	if ( spk_x < win_left || spk_y < win_top ) {
+		synth_write_msg( "error 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;
+		sprintf( info, "window is line %d", (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;
+		}
+		sprintf( info, "%s at line %d, column %d",
+			(win_start) ? "end" : "start",
+			(int)spk_y+1, (int)spk_x+1 );
+	}
+	synth_write_msg( 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_write_msg( "window cleared" );
+}
+
+static void
+speakup_win_enable (struct vc_data *vc )
+{
+	if ( win_start < 2 ) {
+		synth_write_msg( "no window" );
+		return;
+	}
+	win_enabled ^= 1;
+	if ( win_enabled ) synth_write_msg( "window silenced" );
+	else synth_write_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_write_msg( "error" );
+		return;
+	}
+	pb_edit = &punc_info[val];
+	sprintf( buf, "edit  %s, press space when done", pb_edit->name );
+	synth_write_msg( buf );
+	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;
+	short 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_write_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_write_msg( "error" );
+		return;
+	}
+	synth_write_msg( "go to?" );
+	special_handler = handle_goto;
+	return;
+}
+
+static void
+load_help ( void *dummy )
+{
+	request_module( "speakup_keyhelp" );
+	if ( help_handler ) {
+		(*help_handler)(0, KT_SPKUP, SPEAKUP_HELP, 0 );
+	} else synth_write_string( "help module not found" );
+}
+
+#if (LINUX_VERSION_CODE >= 132419)
+static DECLARE_WORK(ld_help, load_help, NULL);
+#define schedule_help schedule_work
+#else
+static struct tq_struct ld_help = { routine: load_help, };
+#define schedule_help schedule_task
+#endif
+
+static void
+speakup_help (struct vc_data *vc )
+{
+	if ( help_handler == NULL ) {
+/* we can't call request_module from this context so schedule it*/
+/* **** note kernel hangs and my wrath will be on you */
+		schedule_help (&ld_help);
+		return;
+	}
+	(*help_handler)(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 = 0, spk_key_locked = 0;
+
+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, NULL
+};
+
+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
+#if (LINUX_VERSION_CODE < 132419)
+speakup_key ( int shift_state, u_char keycode, u_short keysym, u_char up_flag )
+#else
+speakup_key (struct vc_data *vc, int shift_state, int keycode, u_short keysym, int up_flag, struct pt_regs *regs )
+#endif
+{
+	u_char *key_info;
+	u_char type = KTYP( keysym ), value = KVAL( keysym ), new_key = 0;
+	u_char shift_info, offset;
+#if (LINUX_VERSION_CODE >= 132419)
+	tty = vc->vc_tty;
+#endif
+	if ( synth == NULL ) return 0;
+	if ( type >= 0xf0 ) type -= 0xf0;
+	if ( type == KT_PAD && (vc_kbd_led(kbd , VC_NUMLOCK ) ) ) {
+		if ( up_flag ) {
+			spk_keydown = 0;
+			return 0;
+		}
+		value = spk_lastkey = pad_chars[value];
+		spk_keydown++;
+		spk_parked &= 0xfe;
+		goto no_map;
+	}
+	if ( keycode >= MAX_KEY ) goto no_map;
+	if ( ( key_info = our_keys[keycode] ) == 0 ) goto no_map;
+	shift_info = ( shift_state&0x0f ) + key_speakup;
+	offset = shift_table[shift_info];
+	if ( offset && ( new_key = key_info[offset] ) ) {
+		if ( new_key == SPK_KEY ) {
+			if ( !spk_key_locked )
+				key_speakup = ( up_flag ) ? 0 : 16;
+			if ( up_flag || spk_killed ) return 1;
+			spk_shut_up &= 0xfe;
+			do_flush( );
+			return 1;
+		}
+		if ( up_flag ) return 1;
+		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;
+		return 1;
+	}
+	if ( up_flag || spk_killed || type == KT_SHIFT ) return 0;
+	spk_shut_up &= 0xfe;
+	if (!no_intr ) do_flush( );
+	if ( special_handler ) {
+		int status;
+		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 */
+		status = (*special_handler)(vc, type, value, keycode );
+		spk_close_press = 0;
+		if ( status < 0 ) bleep( 9 );
+		return status;
+	}
+	last_keycode = 0;
+	return 0;
+}
+
+#ifdef MODULE
+
+extern void proc_speakup_init( void );
+extern void proc_speakup_remove( void );
+extern void speakup_set_addresses ( spk_con_func, spk_con_func, spk_write_func, spk_con_func, spk_key_func);
+
+static void __exit mod_speakup_exit( void )
+{
+	int i;
+	key_handler[KT_LATIN] = do_latin;
+	key_handler[KT_SPEC] = do_spec;
+	key_handler[KT_CUR] = do_cursor;
+	key_handler[KT_SHIFT] = do_shift;
+	speakup_set_addresses( NULL, NULL, NULL, NULL, NULL );
+	synth_release( );
+	proc_speakup_remove( );
+	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_console[i] = NULL;
+	}
+}
+
+static int __init mod_speakup_init( void )
+{
+int i;
+	spk_t *first_console = (spk_t *) kmalloc (spk_size + 1, GFP_KERNEL );
+	speakup_open( vc_cons[fg_console].d, first_console );
+for ( i = 0; vc_cons[i].d; i++)
+  speakup_allocate(vc_cons[i].d);
+	speakup_set_addresses( speakup_allocate, speakup_bs,
+		speakup_con_write, speakup_con_update, speakup_key );
+	proc_speakup_init( );
+	return 0;
+}
+
+module_init( mod_speakup_init );
+module_exit( mod_speakup_exit );
+
+#endif
diff -puN /dev/null drivers/char/speakup/speakupconf
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakupconf	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,51 @@
+#!/bin/sh
+# script to load/save all the vars in speakup
+# speakupconf save or speakupconf load
+# if root saves in /etc/speakup/<synth_name> else in $HOME/.speakup/<synth_name>
+if [ $UID -eq "0" ]; then
+  SAVEDIR="/etc/speakup"
+else
+  SAVEDIR="$HOME/.speakup"
+fi
+if [ ! -d /proc/speakup ]; then
+  echo "no directory /proc/speakup"
+  exit 0
+fi
+SYNTH=`cat /proc/speakup/synth_name`
+case "$1" in
+*save)
+  if [ ! -d $SAVEDIR ] ; then
+    echo creating $SAVEDIR
+    mkdir $SAVEDIR
+  fi
+  if [ ! -d $SAVEDIR/$SYNTH ] ; then
+    echo creating $SAVEDIR/$SYNTH
+    mkdir $SAVEDIR/$SYNTH
+  fi
+  cd /proc/speakup
+  SAVELIST=`    find . -perm -6 |sed 's/..//' |fgrep -v synth`
+  for f in $SAVELIST; do
+    cp $f $SAVEDIR/$SYNTH/$f
+  done
+;;
+*load)
+  if [ ! -d $SAVEDIR ] ; then
+    echo no directory $SAVEDIR
+    exit 1
+  fi
+  if [ ! -d $SAVEDIR/$SYNTH ] ; then
+    echo no directory $SAVEDIR/$SYNTH
+    exit 1
+  fi
+  cd $SAVEDIR/$SYNTH
+  for f in *; do
+    if [ -w /proc/speakup/$f ]; then
+      cat $f >/proc/speakup/$f
+    fi
+  done
+;;
+*)
+  echo "usage: speakupconf load/save"
+  exit 1
+;;
+esac
diff -puN /dev/null drivers/char/speakup/speakup_decext.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_decext.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,205 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_decext
+#define SYNTH_CLEAR 0x03
+#define PROCSPEECH 0x0b
+#define synth_full( ) ( inb_p( synth_port_tts ) == 0x13 )
+
+static int timeouts = 0;
+static int in_escape = 0;
+
+static int wait_for_xmitr ( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do { /* holding register empty? */
+		check = inb_p( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn ( "%s:  timed out\n", synth->long_name );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do { /* CTS */
+		check = inb_p ( synth_port_tts + UART_MSR );
+		if ( --tmout == 0 ) {
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out ( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr ( ) ) {
+		outb_p ( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static u_char
+spk_serial_in ( void )
+{
+	int lsr, tmout = SPK_SERIAL_TIMEOUT, c;
+	do {
+		lsr = inb_p ( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 )
+			return 0xff;
+	} while ( !( lsr & UART_LSR_DR ) );
+	c = inb_p ( synth_port_tts + UART_RX );
+	return ( u_char ) c;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+static u_char last='\0';
+	synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == '\n' ) ch = 0x0D;
+		if ( synth_full( ) || !spk_serial_out( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		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 );
+				synth_delay( synth_delay_time );
+				return;
+			}
+		}
+		last = ch;
+	}
+	if ( synth_done( ) || !in_escape )
+	spk_serial_out( PROCSPEECH );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush( void )
+{
+	in_escape = 0;
+	synth_immediate( "\033P;10z\033\\" );
+}
+
+static int serprobe( int index )
+{
+		u_char test=0;
+		struct serial_state *ser = spk_serial_init( index );
+		if ( ser == NULL ) return -1;
+		/* ignore any error results, if port was forced */
+	if ( synth_port_forced )
+				return 0;
+	synth_immediate( "\033[;5n\033\\" );
+	if ( ( test = spk_serial_in( ) ) == '\033' )
+		return 0;
+	spk_serial_release( );
+	timeouts = synth_alive = synth_port_tts = 0; /* not ignoring */
+	return -1;
+}
+
+static int synth_probe( void )
+{
+	int i=0, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+		/* check ttyS0-ttyS3 */
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+        }
+        if ( failed ) {
+		pr_info( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info( "%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
+		synth_port_tts, synth_port_tts+7, synth->version );
+	return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive&& wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;
+	}
+	pr_warn( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "[:pe -380]";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "[:dv ap 222]" },
+	{ CAPS_STOP, "[:dv ap 100]" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "[:ra %d]", 7, 0, 9, 150, 25, 0 },
+	{ PITCH, "[:dv ap %d]", 100, 0, 100, 0, 0, 0 },
+	{ VOL, "[:dv gv %d]", 13, 0, 16, 0, 5, 0 },
+	{ PUNCT, "[:pu %c]", 0, 0, 2, 0, 0, "nsa" },
+	{ VOICE, "[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_decext = {"decext", "1.1", "Dectalk External",
+	 init_string, 500, 50, 50, 1000, 0, SF_DEC, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_decpc.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_decpc.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,242 @@
+/*
+* written by David Borowski, david575@golden.net
+
+		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 "dtpc_reg.h"
+
+#define MY_SYNTH synth_dec_pc
+#define PROCSPEECH 0x0b
+#define SYNTH_IO_EXTENT 8
+
+static int synth_portlist[] = { 0x340, 0x350, 0x240, 0x250, 0 };
+static int in_escape = 0, is_flushing = 0;
+static int dt_stat, dma_state = 0;
+
+static inline int dt_getstatus( void )
+{
+	dt_stat =  inb_p( synth_port_tts )|(inb_p( synth_port_tts+1 )<<8);
+	return dt_stat;
+}
+
+static inline void dt_sendcmd( u_int cmd )
+{
+	outb_p( cmd & 0xFF, synth_port_tts );
+	outb_p( (cmd>>8) & 0xFF, synth_port_tts+1 );
+}
+
+static int dt_waitbit( int bit )
+{
+	int timeout = 100;
+	while ( --timeout > 0 ) {
+		if( (dt_getstatus( ) & bit ) == bit ) return 1;
+		udelay( 50 );
+	}
+	return 0;
+}
+
+static int dt_wait_dma( void )
+{
+	int timeout = 100, state = dma_state;
+	if( ! dt_waitbit( STAT_dma_ready ) ) return 0;
+	while ( --timeout > 0 ) {
+		if( (dt_getstatus()&STAT_dma_state) == state ) return 1;
+		udelay( 50 );
+	}
+	dma_state = dt_getstatus( ) & STAT_dma_state;
+	return 1;
+}
+
+int dt_ctrl( u_int cmd )
+{
+	int timeout = 10;
+	if ( !dt_waitbit( STAT_cmd_ready ) ) return -1;
+	outb_p( 0, synth_port_tts+2 );
+	outb_p( 0, synth_port_tts+3 );
+	dt_getstatus( );
+	dt_sendcmd( CMD_control|cmd );
+	outb_p( 0, synth_port_tts+6 );
+	while ( dt_getstatus( ) & STAT_cmd_ready ) {
+		udelay( 20 );
+		if ( --timeout == 0 ) break;
+	}
+	dt_sendcmd( CMD_null );
+	return 0;
+}
+
+static void synth_flush( void )
+{
+	int timeout = 10;
+	if ( is_flushing ) return;
+	is_flushing = 4;
+	in_escape = 0;
+	while ( dt_ctrl( CTRL_flush ) ) {
+		if ( --timeout == 0 ) break;
+udelay( 50 );
+	}
+	for ( timeout = 0; timeout < 10; timeout++ ) {
+		if ( dt_waitbit( STAT_dma_ready ) ) break;
+udelay( 50 );
+	}
+	outb_p( DMA_sync, synth_port_tts+4 );
+	outb_p( 0, synth_port_tts+4 );
+	udelay( 100 );
+	for ( timeout = 0; timeout < 10; timeout++ ) {
+		if ( !( dt_getstatus( ) & STAT_flushing ) ) break;
+udelay( 50 );
+	}
+	dma_state = dt_getstatus( ) & STAT_dma_state;
+	dma_state ^= STAT_dma_state;
+	is_flushing = 0;
+}
+
+static int dt_sendchar( char ch )
+{
+	if( ! dt_wait_dma( ) ) return -1;
+	if( ! (dt_stat & STAT_rr_char) ) return -2;
+	outb_p( DMA_single_in, synth_port_tts+4 );
+	outb_p( ch, synth_port_tts+4 );
+	dma_state ^= STAT_dma_state;
+	return 0;
+}
+
+static int testkernel( void )
+{
+	int status = 0;
+	if ( dt_getstatus( ) == 0xffff ) {
+		status = -1;
+		goto oops;
+	}
+	dt_sendcmd( CMD_sync );
+	if( ! dt_waitbit( STAT_cmd_ready ) ) status = -2;
+	else if ( ( dt_stat&0x8000 ) ) {
+		return 0;
+	} else if ( dt_stat == 0x0dec )
+		pr_warn( "dec_pc at 0x%x, software not loaded\n", synth_port_tts );
+	status = -3;
+oops:	synth_release_region( synth_port_tts, SYNTH_IO_EXTENT );
+	synth_port_tts = 0;
+	return status;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+static u_char last='\0';
+	synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == '\n' ) ch = 0x0D;
+		if ( dt_sendchar( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( ch == '[' ) in_escape = 1;
+		else if ( ch == ']' ) in_escape = 0;
+		else if ( ch <= SPACE ) {
+			if ( !in_escape && strchr( ",.!?;:", last ) )
+				dt_sendchar( PROCSPEECH );
+			if ( jiffies >= jiff_max ) {
+				if ( !in_escape )
+					dt_sendchar( PROCSPEECH );
+				synth_delay( synth_delay_time );
+				return;
+			}
+		}
+		last = ch;
+	}
+	if ( synth_done( ) || !in_escape )
+	dt_sendchar( PROCSPEECH );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+		if ( dt_sendchar ( ch ) )
+			return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static int synth_probe ( void )
+{
+	int i=0, failed=0;
+	pr_info ( "Probing for %s.\n", synth->long_name );
+	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;
+		}
+		synth_port_tts = synth_portlist[i];
+		if (( failed = testkernel( )) == 0 ) break;
+	}
+	if ( failed ) {
+		pr_info ( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info ( "%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
+		synth_port_tts, synth_port_tts + 7, synth->version );
+	return 0;
+}
+
+static void dtpc_release(  void )
+{
+	if (  synth_port_tts )
+		synth_release_region( synth_port_tts, SYNTH_IO_EXTENT );
+	synth_port_tts = 0;
+}
+
+static int synth_is_alive( void )
+{
+	synth_alive = 1;
+	return 1;
+}
+
+static const char init_string[] = "[:pe -380]";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "[:dv ap 200]" },
+	{ CAPS_STOP, "[:dv ap 100]" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "[:ra %d]", 9, 0, 18, 150, 25, 0 },
+	{ PITCH, "[:dv ap %d]", 80, 0, 100, 20, 0, 0 },
+	{ VOL, "[:vo se %d]", 5, 0, 9, 5, 10, 0 },
+	{ PUNCT, "[:pu %c]", 0, 0, 2, 0, 0, "nsa" },
+	{ VOICE, "[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_dec_pc = { "decpc", "1.1", "Dectalk PC",
+	init_string, 500, 50, 50, 1000, 0, SF_DEC, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, dtpc_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_dectlk.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_dectlk.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,221 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_dectlk
+#define SYNTH_CLEAR 0x03
+#define PROCSPEECH 0x0b
+#define synth_full( )  ( inb_p( synth_port_tts ) == 0x13 )
+
+static int timeouts = 0;
+static int in_escape = 0, is_flushing = 0;
+
+static int wait_for_xmitr ( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do { /* holding register empty? */
+		check = inb_p( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn ( "%s:  timed out\n", synth->long_name );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do { /* CTS */
+		check = inb_p ( synth_port_tts + UART_MSR );
+		if ( --tmout == 0 ) {
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out ( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr ( ) ) {
+		outb_p ( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static u_char
+spk_serial_in ( void )
+{
+	int lsr, tmout = SPK_SERIAL_TIMEOUT, c;
+	do {
+		lsr = inb_p ( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 )
+			return 0xff;
+	} while ( !( lsr & UART_LSR_DR ) );
+	c = inb_p ( synth_port_tts + UART_RX );
+	return ( u_char ) c;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+static u_char last='\0';
+	synth_stop_timer( );
+	if ( is_flushing ) {
+		ch = spk_serial_in( );
+		if ( ch != '\001' ) {
+			if ( --is_flushing == 0 )
+				pr_warn ( "flush timeout\n" );
+			synth_delay( synth_delay_time );
+			return;
+		}
+		is_flushing = 0;
+	}
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == '\n' ) ch = 0x0D;
+		if ( synth_full( ) || !spk_serial_out( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		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 );
+				synth_delay( synth_delay_time );
+				return;
+			}
+		}
+		last = ch;
+	}
+	if ( synth_done( ) || !in_escape )
+	spk_serial_out( PROCSPEECH );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush( void )
+{
+	in_escape = 0;
+	spk_serial_out ( SYNTH_CLEAR );
+	is_flushing = 4; /* if no ctl-a in 4, send data anyway */
+}
+
+static int serprobe ( int index )
+{
+	struct serial_state *ser = spk_serial_init( index );
+	u_char test, timeout = 20;
+	if ( ser == NULL ) return -1;
+	outb ( 0x0d, ser->port );
+	/* ignore any error results, if port was forced */
+	if ( synth_port_forced ) return 0;
+	/* check for dectalk express now... */
+	if ( !synth_immediate ( "\x03" ) ) {
+		do {
+			test = spk_serial_in ( );
+			if ( test == 0x01 ) return 0;
+		} while ( --timeout > 0 );
+	}
+	spk_serial_release( );
+	timeouts = synth_alive = synth_port_tts = 0;	/* not ignoring */
+	return -1;
+}
+
+static int synth_probe ( void )
+{
+	int i = 0, failed=0;
+	pr_info ( "Probing for %s.\n", synth->long_name );
+	/* check ttyS0-ttyS3 */
+	for ( i = SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+        }
+        if ( failed ) {
+		pr_info ( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info ( "%s: %03x-%03x, Driver Version %s,\n", synth->long_name,
+		synth_port_tts, synth_port_tts + 7, synth->version );
+	return 0;
+}
+
+static int
+synth_is_alive ( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr ( ) > 0 ) {	/* restart */
+		synth_alive = 1;
+		synth_write_string ( synth->init );
+		return 2;
+	} else
+		pr_warn ( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "[:pe -380][:dv ap 100]";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "[:dv ap 200]" },
+	{ CAPS_STOP, "[:dv ap 100]" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "[:ra %d]", 9, 0, 18, 150, 25, 0 },
+	{ PITCH, "[:dv ap %d]", 80, 0, 100, 20, 0, 0 },
+	{ VOL, "[:dv gv %d]", 13, 0, 14, 0, 5, 0 },
+	{ PUNCT, "[:pu %c]", 0, 0, 2, 0, 0, "nsa" },
+	{ VOICE, "[:n%c]", 0, 0, 9, 0, 0, "phfdburwkv" },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_dectlk = { "dectlk", "1.3", "Dectalk Express",
+	init_string, 500, 50, 50, 1000, 0, SF_DEC, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_drvcommon.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_drvcommon.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,879 @@
+#define KERNEL
+#include <linux/config.h>
+#include <linux/version.h>
+#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/delay.h>	/* for loops_per_sec */
+#include <asm/segment.h>	/* for put_user_byte */
+#include <asm/semaphore.h>
+#include <linux/wait.h>		/* for wait_queue */
+#include <linux/miscdevice.h>	/* for misc_register */
+#include "spk_priv.h"
+#include "serialio.h"
+#include <linux/kmod.h>
+
+#define SYNTH_MINOR   25
+
+static struct serial_state rs_table[] = {
+	SERIAL_PORT_DFNS
+};
+
+#include "synthlist.h"
+static struct spk_synth *synths[16] = {
+#include "synthlist.h"
+	NULL };
+
+#define synthBufferSize 8192	/* currently 8K bytes */
+struct spk_synth *synth = NULL;
+struct spk_synth *module_synth = NULL;
+int synth_port_tts = 0, synth_port_forced = 0;
+volatile int synth_timer_active = 0;	/* indicates when a timer is set */
+	static struct miscdevice synth_device;
+static int misc_registered = 0;
+static char pitch_buff[32] = "";
+static char module_name[32] = "";
+static struct semaphore sem; /* no mo races */
+declare_sleeper( synth_sleeping_list );
+static int module_status = 0;
+declare_timer( synth_timer );
+short synth_delay_time = 500, synth_trigger_time = 50;
+short synth_jiffy_delta = 50, synth_full_time = 1000;
+int synth_alive = 0;
+u_char synth_buffer[synthBufferSize];	/* guess what this is for! */
+u_char *buffer_highwater = synth_buffer+synthBufferSize-100;
+u_char *buffer_end = synth_buffer+synthBufferSize-1;
+volatile u_char *synth_buff_in = synth_buffer, *synth_buff_out = synth_buffer;
+
+struct serial_state *spk_serial_init( int index )
+{
+	int baud = 9600, quot = 0;
+	unsigned int cval = 0;
+	int     i, cflag = CREAD | HUPCL | CLOCAL | B9600 | CS8;
+	struct serial_state *ser = NULL;
+ 	if ( synth_port_forced ) {
+		if ( index > 0 ) return NULL;
+		pr_info ( "probe forced to 0x%x by kernel command line\n",
+			synth_port_forced );
+          for ( i=0; i <= SPK_HI_TTY; i++ )
+            if ( ( rs_table+i )->port == synth_port_forced ) {
+              ser = rs_table+i;
+              break;
+            }
+        } else  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.
+	   __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 */
+	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 );
+	  return NULL;
+	}
+	mdelay( 1 );
+	synth_port_tts = ser->port;
+	return ser;
+}
+
+void spk_serial_release( void )
+{
+	if ( synth_port_tts == 0 ) return;
+	synth_release_region( synth_port_tts, 8 );
+	synth_port_tts = 0;
+}
+
+/* sleep for ms milliseconds */
+void
+synth_delay ( int val )
+{
+        if (val == 0) return;
+	synth_timer.expires = jiffies + val;
+		start_timer( synth_timer );
+	synth_timer_active++;
+}
+
+void
+synth_dummy_catchup( unsigned long data )
+{
+	synth_stop_timer( );
+	synth_done( );
+	return;
+} /* a bogus catchup if no synth */
+
+void
+synth_stop_timer ( void )
+{
+	if ( synth_timer_active )
+		stop_timer ( synth_timer );
+	synth_timer_active = 0;
+}
+
+int synth_done( void )
+{
+	synth_buff_out = synth_buff_in = synth_buffer;
+	if (waitqueue_active(&synth_sleeping_list)) {
+		  wake_up_interruptible(&synth_sleeping_list);
+		return 0;
+	}
+	return 1;
+}
+
+static inline void synth_start( void )
+{
+	if ( !synth_alive )
+		synth_done( );
+	else if ( synth->start )
+		synth->start( );
+	else if (synth_timer_active == 0)
+		synth_delay( synth_trigger_time );
+}
+
+void do_flush( void )
+{
+	synth_stop_timer( );
+	synth_buff_out = synth_buff_in = synth_buffer;
+	if ( synth_alive ) {
+		synth->flush( );
+		if ( synth->flush_wait )
+			synth_delay( ( synth->flush_wait * HZ ) / 1000 );
+		if ( pitch_shift ) {
+			synth_write_string( pitch_buff );
+			pitch_shift = 0;
+		}
+	}
+	if (waitqueue_active(&synth_sleeping_list))
+		wake_up_interruptible(&synth_sleeping_list);
+}
+
+void
+synth_buffer_add ( char ch )
+{
+	if ( synth_buff_in >= buffer_highwater ) {
+		synth_start ( );
+		if ( !waitqueue_active ( &synth_sleeping_list ) )
+			interruptible_sleep_on ( &synth_sleeping_list );
+		if ( synth_buff_in >= buffer_end ) return;
+	}
+	*synth_buff_in++ = ch;
+}
+
+void
+synth_write ( const char *buf, size_t count )
+{
+	while ( count-- )
+		synth_buffer_add ( *buf++ );
+	synth_start ( );
+}
+
+void
+synth_write_string ( const char *buf )
+{
+	while ( *buf )
+		synth_buffer_add ( *buf++ );
+	synth_start ( );
+}
+
+void
+synth_write_msg ( const char *buf )
+{
+	while ( *buf )
+		synth_buffer_add ( *buf++ );
+		synth_buffer_add ( '\n' );
+	synth_start ( );
+}
+
+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 );
+}
+
+int synth_release_region ( unsigned long start, unsigned long n )
+{
+	return release_resource ( &synth_res );
+}
+
+#ifdef CONFIG_PROC_FS
+
+// /proc/synth-specific code
+
+#include <asm/uaccess.h>
+#include <linux/limits.h>
+
+// this is the write handler for /proc/speakup/synth-specific/direct
+static int
+spk_direct_write_proc ( PROC_WRITE_PROTOTYPE )
+{
+	u_char buf[256];
+	int ret = count, bytes;
+	const char *ptr = buffer;
+	if ( synth == NULL ) return -EPERM;
+	while ( count > 0 ) {
+		bytes = MIN ( count, 250 );
+		if ( copy_from_user ( buf, ptr, bytes  ) )
+			return -EFAULT;
+		buf[bytes] = '\0';
+		xlate ( buf );
+		synth_write_string ( buf );
+		ptr += bytes;
+		count -= bytes;
+	}
+	return ret;
+}
+
+proc_var synth_direct = { SYNTH_DIRECT, 0, spk_direct_write_proc, 0 };
+
+#endif
+
+static num_var synth_time_vars[] = {
+	{ DELAY, 0, 100, 100, 2000, 0, 0, 0 },
+	{ TRIGGER, 0, 20, 10, 200, 0, 0, 0 },
+	{ JIFFY, 0, 50, 20, 200, 0, 0, 0 },
+	{ FULL, 0, 400, 200, 10000, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+int synth_init ( char *synth_name )
+{
+	int i;
+	if ( synth_name == NULL ) return 0;
+	sema_init ( &sem, 1 ); /* not sure where else to put this. */
+	if ( strcmp (synth_name, "none" ) == 0 ){
+		synth_release( );
+		 return 0;
+	}
+	for (i = 0; synths[i] != NULL; i++ ) {
+		if (strcmp (synths[i]->name, synth_name ) == 0 )
+			return do_synth_init( synths[i] );
+	}
+	if ( strcmp (synth_name, "reload" ) == 0 ) {
+		if ( module_status == 0 ) return 0;
+		goto try_reload;
+	}
+	sprintf( module_name, "speakup_%s", synth_name );
+try_reload:
+		pr_warn ( "Speakup:  loading module \"%s\"\n", module_name );
+		module_status = request_module( module_name );
+	return module_status;
+}
+
+int do_synth_init ( struct spk_synth *in_synth )
+{
+	num_var *n_var;
+	string_var *s_var;
+	synth_release( );
+	if ( in_synth->checkval != SYNTH_CHECK ) return -EINVAL;
+	synth = in_synth;
+	if ( synth->probe ( ) < 0 ) {
+		pr_warn ( "%s: device probe failed\n", in_synth->name );
+		synth = NULL;
+		return -ENODEV;
+	}
+	synth_time_vars[0].default_val = synth->delay;
+	synth_time_vars[1].default_val = synth->trigger;
+	synth_time_vars[2].default_val = synth->jiffies;
+	synth_time_vars[3].default_val = synth->full;
+	  synth_timer.function = synth->catch_up;
+#if (LINUX_VERSION_CODE >= 132419)
+	  synth_timer.entry.prev = NULL;
+#endif
+	  init_timer ( &synth_timer );
+	  for ( n_var = synth_time_vars; n_var->var_id >= 0; n_var++ )
+	    speakup_register_var( n_var );
+	synth_alive = 1;
+	synth_write_string( synth->init );
+	for ( s_var = synth->string_vars; s_var->var_id >= 0; s_var++ )
+		speakup_register_var( ( num_var * ) s_var );
+	for ( n_var = synth->num_vars; n_var->var_id >= 0; n_var++ )
+		speakup_register_var( n_var );
+	synth_write_string( synth->long_name );
+	synth_write_msg( " found" );
+#ifdef CONFIG_PROC_FS
+	speakup_register_var( (num_var *)&synth_direct );
+#endif
+	synth_flags = synth->flags;
+	return 0;
+}
+
+void
+synth_release ( void )
+{
+	num_var *n_var;
+	string_var *s_var;
+	if ( synth == NULL ) return;
+	if (down_interruptible ( &sem )) return;
+	pr_info ( "releasing synth %s\n", synth->name );
+	for ( s_var = synth->string_vars; s_var->var_id >= 0; s_var++ )
+		speakup_unregister_var( s_var->var_id );
+	for ( n_var = synth_time_vars; n_var->var_id >= 0; n_var++ )
+		speakup_unregister_var( n_var->var_id );
+	for ( n_var = synth->num_vars; n_var->var_id >= 0; n_var++ )
+		speakup_unregister_var( n_var->var_id );
+#ifdef CONFIG_PROC_FS
+	speakup_unregister_var( SYNTH_DIRECT );
+#endif
+	synth_dummy_catchup((unsigned long) NULL );
+	synth_timer.function = synth_dummy_catchup;
+	synth->release( );
+	synth = NULL;
+	up( &sem );
+}
+
+void synth_add ( struct spk_synth *in_synth )
+{
+	int i;
+	for (i = 0; synths[i] != NULL; i++ )
+	if ( in_synth == synths[i] ) return;
+	synths[i++] = in_synth;
+	synths[i] = NULL;
+}
+
+void synth_remove ( struct spk_synth *in_synth )
+{
+	int i;
+	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;
+}
+
+var_header var_headers[] = {
+  { "version", VERSION, VAR_PROC, USER_R, 0, 0, 0 },
+  { "synth_name", SYNTH, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "keymap", KEYMAP, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "silent", SILENT, VAR_PROC, USER_W, 0, 0, 0 },
+  { "punc_some", PUNC_SOME, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "punc_most", PUNC_MOST, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "punc_all", PUNC_ALL, VAR_PROC, USER_R, 0, 0, 0 },
+  { "delimiters", DELIM, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "repeats", REPEATS, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "ex_num", EXNUMBER, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "characters", CHARS, VAR_PROC, USER_RW, 0, 0, 0 },
+  { "synth_direct", SYNTH_DIRECT, VAR_PROC, USER_W, 0, 0, 0 },
+  { "caps_start", CAPS_START, VAR_STRING, USER_RW, 0, str_caps_start, 0 },
+  { "caps_stop", CAPS_STOP, VAR_STRING, USER_RW, 0, str_caps_stop, 0 },
+  { "delay_time", DELAY, VAR_TIME, ROOT_W, 0, &synth_delay_time, 0 },
+  { "trigger_time", TRIGGER, VAR_TIME, ROOT_W, 0, &synth_trigger_time, 0 },
+  { "jiffy_delta", JIFFY, VAR_TIME, ROOT_W, 0, &synth_jiffy_delta, 0 },
+  { "full_time", FULL, VAR_TIME, ROOT_W, 0, &synth_full_time, 0 },
+  { "spell_delay", SPELL_DELAY, VAR_NUM, USER_RW, 0, &spell_delay, 0 },
+  { "bleeps", BLEEPS, VAR_NUM, USER_RW, 0, &bleeps, 0 },
+  { "attrib_bleep", ATTRIB_BLEEP, VAR_NUM, USER_RW, 0, &attrib_bleep, 0 },
+  { "bleep_time", BLEEP_TIME, VAR_NUM, USER_RW, 0, &bleep_time, 0 },
+  { "cursor_time", CURSOR_TIME, VAR_TIME, USER_RW, 0, &cursor_timeout, 0 },
+  { "punc_level", PUNC_LEVEL, VAR_NUM, USER_RW, 0, &punc_level, 0 },
+  { "reading_punc", READING_PUNC, VAR_NUM, USER_RW, 0, &reading_punc, 0 },
+  { "say_control", SAY_CONTROL, VAR_NUM, USER_RW, 0, &say_ctrl, 0 },
+  { "say_word_ctl", SAY_WORD_CTL, VAR_NUM, USER_RW, 0, &say_word_ctl, 0 },
+  { "no_interrupt", NO_INTERRUPT, VAR_NUM, USER_RW, 0, &no_intr, 0 },
+  { "key_echo", KEY_ECHO, VAR_NUM, USER_RW, 0, &key_echo, 0 },
+  { "bell_pos", BELL_POS, VAR_NUM, USER_RW, 0, &bell_pos, 0 },
+  { "rate", RATE, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "pitch", PITCH, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "vol", VOL, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "tone", TONE, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "punct", PUNCT, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "voice", VOICE, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "freq", FREQ, VAR_NUM, USER_RW, 0, 0, 0 },
+  { "lang", LANG, VAR_NUM, USER_RW, 0, 0, 0 }
+};
+
+var_header *var_ptrs[MAXVARS] = { 0, 0, 0 };
+
+char *
+speakup_s2i ( char *start, short *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;
+}
+
+short punc_masks[] = { 0, SOME, MOST, PUNC, PUNC|B_SYM };
+
+// handlers for setting vars
+int
+set_num_var( short input, var_header *var, int how )
+{
+	short val, ret = 0;
+	short *p_val = var->p_val;
+	int l;
+	char buf[32], *cp;
+	num_var *var_data = var->data;
+	if ( var_data == NULL ) return E_UNDEF;
+	if ( how == E_DEFAULT ) {
+		val = var_data->default_val;
+		ret = SET_DEFAULT;
+	} else {
+		if ( how == E_SET ) val = input;
+		else val = var_data->value;
+		if ( how == E_INC ) val += input;
+		else if ( how == E_DEC ) val -= input;
+		if ( val < var_data->low || val > var_data->high )
+			return E_RANGE;
+	}
+	var_data->value = val;
+	if ( var->var_type == VAR_TIME && p_val != 0 ) {
+		*p_val = ( val * HZ + 1000 - HZ ) / 1000;
+		return ret;
+	}
+	if ( p_val != 0 ) *p_val = val;
+	if ( var->var_id == PUNC_LEVEL ) {
+		punc_mask = punc_masks[val];
+	return ret;
+	}
+	if ( var_data->multiplier != 0 )
+		val *= var_data->multiplier;
+	val += var_data->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->synth_fmt ) return ret;
+	if ( var->var_id == PITCH ) cp = pitch_buff;
+	else cp = buf;
+	if ( !var_data->out_str )
+		l = sprintf( cp, var_data->synth_fmt, (int)val );
+	else l = sprintf( cp, var_data->synth_fmt, var_data->out_str[val] );
+	synth_write_string( cp );
+	return ret;
+}
+
+static int
+set_string_var( char *page, var_header *var, int len )
+{
+	int ret = 0;
+	string_var *var_data = var->data;
+	if ( var_data == NULL ) return E_UNDEF;
+	if ( len > MAXVARLEN )
+		return -E_TOOLONG;
+	if ( !len ) {
+	if ( !var_data->default_val ) return 0;
+		ret = SET_DEFAULT;
+		if ( !var->p_val ) var->p_val = var_data->default_val;
+		if ( var->p_val != var_data->default_val )
+			strcpy( (char *)var->p_val, var_data->default_val );
+		} else if ( var->p_val )
+			strcpy( (char *)var->p_val, page );
+	else return -E_TOOLONG;
+	return ret;
+}
+
+	var_header * get_var_header( short var_id )
+{
+	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;
+}
+
+#ifdef CONFIG_PROC_FS
+// this is the write handler for /proc/speakup vars
+static int
+speakup_vars_write_proc ( PROC_WRITE_PROTOTYPE )
+{
+  var_header *p_header = data;
+	int len = count, ret = 0;
+	char *page = ( char * ) __get_free_page ( GFP_KERNEL );
+	char *v_name = p_header->name, *cp;
+	num_var *var_data;
+	short value;
+	if ( !page ) return -ENOMEM;
+	if ( copy_from_user ( page, buffer, count ) ) {
+		ret = -EFAULT;
+		goto out;
+	}
+	if ( page[len - 1] == '\n' ) --len;
+	page[len] = '\0';
+	cp = xlate( page );
+	switch( p_header->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, p_header, len );
+			if ( ret != E_RANGE ) break;
+	var_data = p_header->data;
+			pr_warn( "value for %s out of range, expect %d to %d\n",
+			v_name, (int)var_data->low, (int)var_data->high );
+			break;
+		case VAR_STRING:
+			len = strlen( page );
+			ret = set_string_var( page, p_header, len );
+			if ( ret != E_TOOLONG ) break;
+			pr_warn( "value too long for %s\n", v_name );
+			break;
+		default:
+			pr_warn( "%s unknown type %d\n",
+				p_header->name, ( int )p_header->var_type );
+		break;
+	}
+out:
+	if ( ret == SET_DEFAULT )
+		pr_info( "%s reset to default value\n", v_name );
+	free_page ( ( unsigned long ) page );
+	return count;
+}
+
+// this is the read handler for /proc/speakup vars
+static int
+speakup_vars_read_proc ( PROC_READ_PROTOTYPE )
+{
+	var_header *var = ( var_header * )data;
+	num_var *n_var = var->data;
+	char ch, *cp, *cp1;
+	*start = 0;
+	*eof = 1;
+	switch( var->var_type ) {
+		case VAR_NUM:
+		case VAR_TIME:
+			return sprintf( page, "%d\n", ( int )n_var->value );
+			break;
+		case VAR_STRING:
+			cp1 = page;
+			*cp1++ = '"';
+			for ( cp = (char *)var->p_val; ( ch = *cp ); cp++ ) {
+				if ( ch >= ' ' && ch < '~' )
+					*cp1++ = ch;
+				else
+					cp1 += sprintf( cp1, "\\""x%02x", ch );
+			}
+			*cp1++ = '"';
+			*cp1++ = '\n';
+			*cp1 = '\0';
+			return cp1-page;
+			break;
+		default:
+			return sprintf( page, "oops bad type %d\n",
+				( int )var->var_type );
+	}
+	return 0;
+}
+
+static const char spk_dir[] = "speakup";
+static struct proc_dir_entry *dir_ent = 0;
+
+static int
+spk_make_proc( var_header *p_header )
+{
+	struct proc_dir_entry *ent = p_header->proc_entry;
+	char *name = p_header->name;
+	proc_var *p_var;
+	if ( dir_ent == 0 || p_header->proc_mode == 0 || ent != 0 ) return 0;
+	ent = create_proc_entry ( name, p_header->proc_mode, dir_ent );
+	if ( !ent ) {
+		pr_warn( "Unable to create /proc/%s/%s entry.\n",
+			spk_dir, name );
+		return -1;
+	}
+	if ( p_header->var_type == VAR_PROC ) {
+		p_var = ( proc_var * )p_header->data;
+		if ( p_header->proc_mode&S_IRUSR )
+			ent->read_proc = p_var->read_proc;
+		if ( p_header->proc_mode&S_IWUSR )
+			ent->write_proc = p_var->write_proc;
+	} else {
+		if ( p_header->proc_mode&S_IRUSR )
+			ent->read_proc = speakup_vars_read_proc;
+		if ( p_header->proc_mode&S_IWUSR )
+			ent->write_proc = speakup_vars_write_proc;
+	}
+	ent->data = ( void * )p_header;
+	p_header->proc_entry = ( void * ) ent;
+	return 0;
+}
+
+#endif
+
+int
+speakup_register_var( num_var *var )
+{
+	static char nothing[2] = "\0";
+	int i, var_id = var->var_id;
+	var_header *p_header;
+	string_var *s_var;
+	if ( var_id < 0 || var_id >= MAXVARS ) return -1;
+	if ( var_ptrs[0] == 0 ) {
+		for ( i = 0; i < MAXVARS; i++ ) {
+			p_header = &var_headers[i];
+			var_ptrs[p_header->var_id] = p_header;
+			p_header->data = 0;
+		}
+	}
+	p_header = var_ptrs[var_id];
+	if ( p_header->data != 0 ) return 0;
+	p_header->data  = var;
+	switch ( p_header->var_type ) {
+		case VAR_STRING:
+			s_var = ( string_var * )var;
+			set_string_var( nothing, p_header, 0 );
+			break;
+		case VAR_NUM:
+		case VAR_TIME:
+			set_num_var( 0, p_header, E_DEFAULT );
+			break;
+	}
+#ifdef CONFIG_PROC_FS
+	return spk_make_proc( p_header );
+#else
+	return 0;
+#endif
+}
+
+void
+speakup_unregister_var( short var_id )
+{
+	var_header *p_header;
+	if ( var_id < 0 || var_id >= MAXVARS ) return;
+	p_header = var_ptrs[var_id];
+	p_header->data = 0;
+#ifdef CONFIG_PROC_FS
+	if ( dir_ent != 0 && p_header->proc_entry != 0 )
+		remove_proc_entry( p_header->name, dir_ent );
+	p_header->proc_entry = 0;
+#endif
+}
+
+// called by proc_root_init( ) to initialize the /proc/speakup subtree
+void __init
+proc_speakup_init ( void )
+{
+	int i;
+	var_header *p_header;
+	proc_var *pv = spk_proc_vars;
+/* if we requested a module at startup it will not load as root not mounted
+ * so let's try to load here as root should be mounted now */
+	speakup_register_devsynth ( );
+#ifdef CONFIG_PROC_FS
+	dir_ent = create_proc_entry ( spk_dir, S_IFDIR, 0 );
+	if ( !dir_ent ) {
+		pr_warn( "Unable to create /proc/%s entry.\n", spk_dir );
+		return;
+	}
+	while ( pv->var_id >= 0 ) {
+		speakup_register_var( ( void * )pv );
+		pv++;
+	}
+		for ( i = 0; i < MAXVARS; i++ ) {
+			p_header = &var_headers[i];
+		if ( p_header->data != 0 ) spk_make_proc( p_header );
+	}
+#endif
+}
+
+void
+proc_speakup_remove ( void )
+{
+	int i;
+		for ( i = 0; i < MAXVARS; i++ )
+			speakup_unregister_var( i );
+		pr_info( "speakup: unregistering synth device /dev/synth\n" );
+	misc_deregister( &synth_device );
+	misc_registered = 0;
+#ifdef CONFIG_PROC_FS
+	if ( dir_ent != 0 )
+		remove_proc_entry( spk_dir, NULL );
+#endif
+}
+
+// provide a file to users, so people can send to /dev/synth
+
+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;
+	u_char buf[256];
+	if ( synth == NULL ) return -ENODEV;
+	while ( count > 0 ) {
+		bytes = MIN ( count, sizeof ( buf ) );
+		if ( copy_from_user ( buf, ptr, bytes ) )
+			return -EFAULT;
+		count -= bytes;
+		ptr += bytes;
+		synth_write ( buf, bytes );
+	}
+	return ( ssize_t ) nbytes;
+}
+
+static int
+speakup_file_ioctl ( struct inode *inode, struct file *file,
+		    unsigned int cmd, unsigned long arg )
+{
+	return 0;		// silently ignore
+}
+
+static ssize_t
+speakup_file_read ( struct file *fp, char *buf, size_t nbytes, loff_t * ppos )
+{
+	return 0;
+}
+
+static int synth_file_inuse = 0;
+
+static int
+speakup_file_open ( struct inode *ip, struct file *fp )
+{
+	if ( synth_file_inuse )
+		return -EBUSY;
+	else if ( synth == NULL )
+		return -ENODEV;
+	synth_file_inuse++;
+	return 0;
+}
+
+static int
+speakup_file_release ( struct inode *ip, struct file *fp )
+{
+	synth_file_inuse = 0;
+	return 0;
+}
+
+static struct file_operations synth_fops = {
+	read:speakup_file_read,
+	write:speakup_file_write,
+	ioctl:speakup_file_ioctl,
+	open:speakup_file_open,
+	release:speakup_file_release,
+};
+
+void
+speakup_register_devsynth ( void ) {
+	if ( misc_registered != 0 ) return;
+	misc_registered = 1;
+	memset( &synth_device, 0, sizeof( synth_device ) );
+/* zero it so if register fails, deregister will not ref invalid ptrs */
+	synth_device.minor = SYNTH_MINOR;
+	synth_device.name = "synth";
+	synth_device.fops = &synth_fops;
+	if ( misc_register ( &synth_device ) )
+		pr_warn(
+			"Couldn't initialize miscdevice /dev/synth.\n" );
+	else
+		pr_info(
+		    "initialized device: /dev/synth, node ( MAJOR 10, MINOR 25 )\n" );
+}
+
+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;
+}
+
+/* exported symbols needed by synth modules */
+EXPORT_SYMBOL(synth_init);
+EXPORT_SYMBOL(do_synth_init);
+EXPORT_SYMBOL(spk_serial_init);
+EXPORT_SYMBOL(spk_serial_release);
+EXPORT_SYMBOL(synth);
+EXPORT_SYMBOL(synth_alive);
+EXPORT_SYMBOL(synth_buffer);
+EXPORT_SYMBOL(synth_buff_in);
+EXPORT_SYMBOL(synth_buff_out);
+EXPORT_SYMBOL(synth_delay);
+EXPORT_SYMBOL(synth_delay_time);
+EXPORT_SYMBOL(synth_done);
+EXPORT_SYMBOL(synth_full_time);
+EXPORT_SYMBOL(synth_jiffy_delta);
+EXPORT_SYMBOL(synth_port_forced);
+EXPORT_SYMBOL(synth_port_tts);
+EXPORT_SYMBOL(synth_request_region);
+EXPORT_SYMBOL(synth_release_region);
+EXPORT_SYMBOL(synth_release);
+EXPORT_SYMBOL(synth_add);
+EXPORT_SYMBOL(synth_remove);
+EXPORT_SYMBOL(synth_stop_timer);
+EXPORT_SYMBOL(synth_write_string);
+EXPORT_SYMBOL(synth_write_msg);
+EXPORT_SYMBOL(synth_write);
+MODULE_AUTHOR("Kirk Reiser <kirk@braille.uwo.ca>");
+MODULE_DESCRIPTION("Speakup module required by all synthesizer specific modules");
+MODULE_LICENSE("GPL");
diff -puN /dev/null drivers/char/speakup/speakup_dtlk.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_dtlk.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,219 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "speakup_dtlk.h" /* local header file for DoubleTalk values */
+
+#define MY_SYNTH synth_dtlk
+#define PROCSPEECH 0x00
+#define synth_readable() ((synth_status = inb_p(synth_port_tts)) & TTS_READABLE)
+#define synth_full() ((synth_status = inb_p(synth_port_tts)) & TTS_ALMOST_FULL)
+
+static int synth_lpc;
+static unsigned int synth_portlist[] =
+		{ 0x25e, 0x29e, 0x2de, 0x31e, 0x35e, 0x39e, 0 };
+static u_char synth_status = 0;
+
+static inline void spk_out(const char ch)
+{
+	int tmout = 100000;
+	while (((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) == 0);
+	outb_p(ch, synth_port_tts);
+	while ((((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) != 0)
+		&& (--tmout != 0) );
+}
+
+static void do_catch_up(unsigned long data)
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	synth_stop_timer();
+	synth_status = inb_p(synth_port_tts);
+	while (synth_buff_out < synth_buff_in) {
+		if (synth_status & TTS_ALMOST_FULL) {
+			synth_delay(synth_full_time);
+			return;
+		}
+		ch = *synth_buff_out++;
+		if (ch == 0x0a) ch = PROCSPEECH;
+		spk_out( ch );
+		if (jiffies >= jiff_max && ch == SPACE) {
+			spk_out(PROCSPEECH);
+			synth_delay(synth_delay_time);
+			return;
+		}
+	}
+	spk_out(PROCSPEECH);
+	synth_done( );
+}
+
+static char *synth_immediate(char *buf )
+{
+	u_char ch;
+	synth_status = inb_p(synth_port_tts);
+	while ( (ch = (u_char)*buf ) ) {
+		if (synth_status & TTS_ALMOST_FULL)
+			return buf;
+		if ( ch == 0x0a ) ch = PROCSPEECH;
+		spk_out(ch);
+		buf++;
+	}
+	return 0;
+}
+
+static void synth_flush(void)
+{
+	outb_p(SYNTH_CLEAR, synth_port_tts);
+	while (((synth_status = inb_p(synth_port_tts)) & TTS_WRITABLE) != 0);
+	}
+
+static char synth_read_tts(void)
+{
+	u_char ch;
+	while (((synth_status = inb_p(synth_port_tts)) & TTS_READABLE) == 0);
+	ch = synth_status & 0x7f;
+	outb_p(ch, synth_port_tts);
+	while ((inb_p(synth_port_tts) & TTS_READABLE) != 0);
+return (char) ch;
+}
+
+/* interrogate the DoubleTalk PC and return its settings */
+static struct synth_settings * synth_interrogate(void)
+{
+	u_char *t;
+static char buf[sizeof(struct synth_settings) + 1];
+int total, i;
+static struct synth_settings status;
+	synth_immediate("\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;
+	status.serial_number = t[0] + t[1]*256; /* serial number is little endian */
+	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(void)
+{
+		unsigned int port_val = 0;
+	int i = 0;
+	struct synth_settings *sp;
+	pr_info("Probing for DoubleTalk.\n");
+	if (synth_port_forced) {
+		synth_port_tts = synth_port_forced;
+		pr_info("probe forced to %x by kernel command line\n", synth_port_tts);
+		if (synth_request_region(synth_port_tts-1, SYNTH_IO_EXTENT)) {
+			pr_warn("sorry, port already reserved\n");
+			return -EBUSY;
+		}
+		port_val = inw(synth_port_tts-1);
+		synth_lpc = synth_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]);
+			if ((port_val &= 0xfbff) == 0x107f) {
+	synth_lpc = synth_portlist[i];
+	synth_port_tts = synth_lpc+1;
+	break;
+			}
+			synth_release_region(synth_portlist[i], SYNTH_IO_EXTENT);
+		}
+	}
+	if ((port_val &= 0xfbff) != 0x107f) {
+		pr_info("DoubleTalk PC:  not found\n");
+		return -ENODEV;
+	}
+	while (inw_p(synth_lpc) != 0x147f ); /* wait until it's ready */
+	sp = synth_interrogate();
+	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 int synth_is_alive(void)
+{
+	return 1;	/* I'm *INVINCIBLE* */
+}
+
+static void
+dtlk_release( void )
+{
+	if ( synth_port_tts )
+		synth_release_region(synth_port_tts-1, SYNTH_IO_EXTENT);
+	synth_port_tts = 0;
+}
+
+static const char init_string[] = "\x01@\x01\x31y";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x01+35p" },
+	{ CAPS_STOP, "\x01-35p" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x01%ds", 8, 0, 9, 0, 0, 0 },
+	{ PITCH, "\x01%dp", 50, 0, 99, 0, 0, 0 },
+	{ VOL, "\x01%dv", 5, 0, 9, 0, 0, 0 },
+	{ TONE, "\x01%dx", 1, 0, 2, 0, 0, 0 },
+	{ PUNCT, "\x01%db", 7, 0, 15, 0, 0, 0 },
+	{ VOICE, "\x01%do", 0, 0, 7, 0, 0, 0 },
+	{ FREQ, "\x01%df", 5, 0, 9, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_dtlk = {"dtlk", "1.1", "DoubleTalk PC",
+			   init_string, 500, 30, 50, 1000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, dtlk_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_dtlk.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_dtlk.h	2005-09-07 19:39:50.000000000 -0700
@@ -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 */
+};
diff -puN /dev/null drivers/char/speakup/speakup_keyhelp.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_keyhelp.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,294 @@
+/* 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/version.h>
+#include <linux/keyboard.h>
+#include "spk_priv.h"
+
+extern u_char *our_keys[];
+extern special_func special_handler;
+extern special_func help_handler;
+#define MAXFUNCS 130
+#define MAXKEYS 256
+static u_short key_offsets[MAXFUNCS], key_buf[MAXKEYS];
+static u_short masks[] = { 32, 16, 8, 4, 2, 1 };
+static char help_info[] =
+	"press space to leav help, cursor up or down to scroll, or a letter to go to commands in list";
+static char *statenames[] = {
+	" double", " speakup", " alt",
+	" ctrl", " altgr", " shift"
+};
+static char *keynames[] = {
+	"escape", "1", "2", "3", "4",
+	"5", "6", "7", "8", "9",
+	"0", "minus", "equal", "back space", "tab",
+	"q", "w", "e", "r", "t",
+	"y", "u", "i", "o", "p",
+	"left brace", "right brace", "enter", "left control", "a",
+	"s", "d", "f", "g", "h",
+	"j", "k", "l", "semicolon", "apostrophe",
+	"accent", "left shift", "back slash", "z", "x",
+	"c", "v", "b", "n", "m",
+	"comma", "dot", "slash", "right shift", "keypad asterisk",
+	"left alt", "space", "caps lock", "f1", "f2",
+	"f3", "f4", "f5", "f6", "f7",
+	"f8", "f9", "f10", "num lock", "scroll lock",
+	"keypad 7", "keypad 8", "keypad 9", "keypad minus", "keypad 4",
+	"keypad 5", "keypad 6", "keypad plus", "keypad 1", "keypad 2",
+	"keypad 3", "keypad 0", "keypad dot", "103rd", "f13",
+	"102nd", "f11", "f12", "f14", "f15",
+	"f16", "f17", "f18", "f19", "f20",
+	"keypad enter", "right control", "keypad slash", "sysrq", "right alt",
+	"line feed", "home", "up", "page up", "left",
+	"right", "end", "down", "page down", "insert",
+	"delete", "macro", "mute", "volume down", "volume up",
+	"power", "keypad equal", "keypad plusminus", "pause", "f21",
+	"f22", "f23", "f24", "keypad comma", "left meta",
+	"right meta", "compose", "stop", "again", "props",
+	"undo", "front", "copy", "open", "paste",
+	"find", "cut", "help", "menu", "calc",
+	"setup", "sleep", "wakeup", "file", "send file",
+	"delete file", "transfer", "prog1", "prog2", "www",
+	"msdos", "coffee", "direction", "cycle windows", "mail",
+	"bookmarks", "computer", "back", "forward", "close cd",
+	"eject cd", "eject close cd", "next song", "play pause", "previous song",
+	"stop cd", "record", "rewind", "phone", "iso",
+	"config", "home page", "refresh", "exit", "move",
+	"edit", "scroll up", "scroll down", "keypad left paren", "keypad right paren",
+};
+
+static short letter_offsets[26];
+
+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 char *funcnames[] = {
+	"attribute bleep decrement", "attribute bleep increment",
+	"bleeps decrement", "bleeps increment",
+	"character, first", "character, last",
+	"character, say current",
+	"character, say hex and decimal", "character, say next",
+	"character, say phonetic", "character, say previous",
+	"cursor park", "cut",
+	"edit delimiters", "edit exnum",
+	"edit most", "edit repeats", "edit some",
+	"go to", "go to bottom edge", "go to left edge",
+	"go to right edge", "go to top edge", "help",
+	"line, say current", "line, say next",
+	"line, say previous", "line, say with indent",
+	"paste", "pitch decrement", "pitch increment",
+	"punctuation decrement", "punctuation increment",
+	"punc  level decrement", "punc level increment",
+	"quiet",
+	"rate decrement", "rate increment",
+	"reading punctuation decrement", "reading punctuation increment",
+	"say attributes",
+	"say from left", "say from top",
+	"say position", "say screen",
+	"say to bottom", "say to right",
+	"speakup", "speakup lock",
+	"speakup off", "speech kill",
+	"spell delay decrement", "spell delay increment",
+	"spell word", "spell word phoneticly",
+	"tone decrement", "tone increment",
+	"voice decrement", "voice increment",
+	"volume decrement", "volume increment",
+	"window, clear", "window, say",
+	"window, set", "window, silence",
+	"word, say current", "word, say next",
+	"word, say previous", 0
+};
+
+static u_char *state_tbl;
+static int cur_item = 0, nstates = 0;
+
+static void build_key_data( void )
+{
+	u_char *kp, counters[MAXFUNCS], ch, ch1;
+	u_short *p_key = key_buf, 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]--;
+			if ( !(offset = key_offsets[ch1]) ) continue;
+			p_key = key_buf + 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_write_string( statenames[i] );
+	}
+	synth_write_string( " " );
+		synth_write_msg( keynames[--key] );
+}
+
+static 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 ( type == KT_LATIN ) {
+		if ( ch == SPACE ) {
+			special_handler = NULL;
+#if (LINUX_VERSION_CODE < 132419)
+			MOD_DEC_USE_COUNT;
+#endif
+			synth_write_msg( "leaving help" );
+			return 1;
+		}
+		ch |= 32; /* lower case */
+		if ( ch < 'a' || ch > 'z' ) return -1;
+		if ( letter_offsets[ch-'a'] == -1 ) {
+			synth_write_string( "no commands for " );
+			synth_write( &ch, 1 );
+			synth_write( "\n", 1 );
+			return 1;
+		}
+	cur_item	= letter_offsets[ch-'a'];
+	} else if ( type == KT_CUR ) {
+		if ( ch == 0 && funcnames[cur_item+1] != NULL )
+			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 = help_handler;
+#if (LINUX_VERSION_CODE < 132419)
+		MOD_INC_USE_COUNT;
+#endif
+		synth_write_msg( help_info );
+		build_key_data( ); /* rebuild each time in case new mapping */
+		return 1;
+	} else {
+		name = NULL;
+		if ( type != KT_SPKUP ) {
+			synth_write_msg( keynames[key-1] );
+			return 1;
+		}
+		for ( i = 0; funcvals[i] != 0 && !name; i++ ) {
+			if ( ch == funcvals[i] )
+				name = funcnames[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_write_string( "is " );
+		synth_write_msg( name );
+		return 1;
+	}
+	name = funcnames[cur_item];
+	func = funcvals[cur_item];
+	synth_write_string( name );
+	if ( key_offsets[func] == 0 ) {
+		synth_write_msg( " is unassigned" );
+		return 1;
+	}
+	p_keys = key_buf + key_offsets[func];
+	for ( n = 0; p_keys[n]; n++ ) {
+		val = p_keys[n];
+		if ( n > 0 ) synth_write_string( "or " );
+		say_key( val );
+	}
+	return 1;
+}
+
+static void __exit mod_help_exit( void )
+{
+	help_handler = 0;
+}
+
+static int __init mod_help_init( void )
+{
+	char start = SPACE;
+	int i;
+state_tbl = our_keys[0]+SHIFT_TBL_SIZE+2;
+	for (i = 0; i < 26; i++ ) letter_offsets[i] = -1;
+	for ( i = 0; funcnames[i]; i++ ) {
+		if ( start == *funcnames[i] ) continue;
+		start = *funcnames[i];
+		letter_offsets[(start&31)-1] = i;
+	}
+	help_handler = handle_help;
+	return 0;
+}
+
+module_init( mod_help_init );
+module_exit( mod_help_exit );
+MODULE_AUTHOR("David Borowski");
+MODULE_DESCRIPTION("Speakup keyboard help MODULE");
+MODULE_LICENSE("GPL");
diff -puN /dev/null drivers/char/speakup/speakup_keypc.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_keypc.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,189 @@
+/*
+* 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
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+
+#define MY_SYNTH synth_keypc
+#define SYNTH_IO_EXTENT	0x04
+#define SWAIT udelay( 70 )
+#define synth_writable( ) ( inb_p( synth_port ) & 0x10 )
+#define synth_readable( ) ( inb_p( synth_port ) & 0x10 )
+#define synth_full( ) ( ( inb_p( synth_port ) & 0x80 ) == 0 )
+#define PROCSPEECH 0x1f
+#define SYNTH_CLEAR 0x03
+
+static int synth_port;
+static unsigned int synth_portlist[] =
+    { 0x2a8, 0 };
+
+static int
+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 0;
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	int timeout;
+	while (  (  ch = *buf ) ) {
+		if ( ch == 0x0a ) ch = PROCSPEECH;
+		if ( synth_full( ) )
+			return buf;
+	timeout = 1000;
+		while ( synth_writable( ) )
+			if ( --timeout <= 0 ) return (char *) oops( );
+		outb_p( ch, synth_port );
+		SWAIT;
+	buf++;
+	}
+	return 0;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	int timeout;
+	synth_stop_timer( );
+	while (  synth_buff_out < synth_buff_in ) {
+ 		if ( synth_full( ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+	timeout = 1000;
+		while ( synth_writable( ) )
+			if ( --timeout <= 0 ) break;
+		if ( timeout <= 0 ) {
+			oops( );
+			break;
+		}
+		ch = *synth_buff_out++;
+	if ( ch == 0x0a ) 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 );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	timeout = 1000;
+		while ( synth_writable( ) )
+			if ( --timeout <= 0 ) break;
+		if ( timeout <= 0 ) oops( );
+			else
+	outb_p( PROCSPEECH, synth_port );
+	synth_done(  );
+}
+
+static void synth_flush( void )
+{
+	outb_p( SYNTH_CLEAR, synth_port );
+}
+
+static int synth_probe( void )
+{
+	unsigned int port_val = 0;
+	int i = 0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	if ( synth_port_forced ) {
+		synth_port = synth_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 );
+	return 0;
+}
+
+static void keynote_release(  void )
+{
+	if (  synth_port )
+		synth_release_region( synth_port, SYNTH_IO_EXTENT );
+	synth_port = 0;
+}
+
+static int synth_is_alive( void )
+{
+	synth_alive = 1;
+	return 1;
+}
+
+static const char init_string[] = "[t][n7,1][n8,0]";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "[f130]" },
+	{ CAPS_STOP, "[f90]" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\04%c ", 8, 0, 10, 81, -8, 0 },
+	{ PITCH, "[f%d]", 5, 0, 9, 40, 10, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_keypc = {"keypc", "1.1", "Keynote PC",
+	 init_string, 500, 50, 50, 1000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, keynote_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL };
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_ltlk.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_ltlk.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,215 @@
+/*
+ * originally written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#include "speakup_dtlk.h" /* local header file for LiteTalk values */
+
+#define MY_SYNTH synth_ltlk
+#define PROCSPEECH 0x0d
+#define synth_full( ) ( !( inb( synth_port_tts + UART_MSR ) & UART_MSR_CTS ) )
+
+static inline int wait_for_xmitr( void )
+{
+	static int timeouts = 0;	/* sequential number of timeouts */
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do { /* holding register empty? */
+		check = inb( synth_port_tts + UART_LSR );
+    		if ( --tmout == 0 ) {
+    			pr_warn( "%s:  register timed out\n", synth->long_name );
+			timeouts++;
+    			return 0;
+    		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do { /* CTS */
+		check = inb( synth_port_tts + UART_MSR );
+    		if ( --tmout == 0 ) {
+    			timeouts++;
+    			return 0;
+    		}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr( ) ) {
+		outb( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static unsigned char spk_serial_in( void )
+{
+	int c, lsr, tmout = SPK_SERIAL_TIMEOUT;
+	do {
+		lsr = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn( "time out while waiting for input.\n" );
+			return 0xff;
+		}
+	} while ( ( lsr & UART_LSR_DR ) != UART_LSR_DR );
+	c = inb( synth_port_tts + UART_RX );
+	return ( unsigned char ) c;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+	synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+		if ( !spk_serial_out( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && ch == SPACE ) {
+			spk_serial_out( PROCSPEECH );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	spk_serial_out( PROCSPEECH );
+	synth_done ( );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+	  outb( ch, synth_port_tts );
+	else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush( void )
+{
+	spk_serial_out( SYNTH_CLEAR );
+}
+
+/* interrogate the LiteTalk and print its settings */
+static void synth_interrogate( void )
+{
+	unsigned char *t, i;
+	unsigned char buf[50], rom_v[20];
+	synth_immediate( "\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++ > 48) break;
+	}
+	rom_v[i] = 0;
+	pr_info( "%s: ROM version: %s\n", synth->long_name, rom_v );
+}
+
+static int serprobe( int index )
+{
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	outb( 0, ser->port );
+	mdelay( 1 );
+	outb( '\r', ser->port );
+	/* ignore any error results, if port was forced */
+	if ( synth_port_forced ) return 0;
+	/* check for device... */
+	if ( !synth_immediate( "\x18" ) ) return 0;
+	spk_serial_release( );
+	synth_alive = 0; /* try next port */
+	return -1;
+}
+
+static int synth_probe( void )
+{
+	int i, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+	}
+	if ( failed ) {
+	  pr_info( "%s:  not found\n", synth->long_name );
+	  return -ENODEV;
+	}
+	synth_interrogate( );
+	pr_info( "%s: at  %03x-%03x, driver %s\n", synth->long_name,
+	       synth_port_tts, synth_port_tts + 7, synth->version );
+	return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( !synth_alive && wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;
+	} else pr_warn( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "\01@\x01\x31y\n\0";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x01+35p" },
+	{ CAPS_STOP, "\x01-35p" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x01%ds", 8, 0, 9, 0, 0, 0 },
+	{ PITCH, "\x01%dp", 50, 0, 99, 0, 0, 0 },
+	{ VOL, "\x01%dv", 5, 0, 9, 0, 0, 0 },
+	{ TONE, "\x01%dx", 1, 0, 2, 0, 0, 0 },
+	{ PUNCT, "\x01%db", 7, 0, 15, 0, 0, 0 },
+	{ VOICE, "\x01%do", 0, 0, 7, 0, 0, 0 },
+	{ FREQ, "\x01%df", 5, 0, 9, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_ltlk = { "ltlk", "1.1", "LiteTalk",
+	init_string, 500, 50, 50, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakupmap.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakupmap.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,64 @@
+	119, 61, 6,
+	0, 16, 17, 32, 20, 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, 0, 0, 0, 0,
+	10, 0, 4, 0, 0, 0, 0,
+	11, 0, 0, 0, 0, 1, 0,
+	12, 0, 27, 33, 0, 0, 0,
+	21, 0, 29, 0, 0, 17, 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, 0, 0, 18, 0,
+	28, 0, 3, 0, 0, 26, 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, 0, 0, 7, 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, 6, 0, 19, 0,
+	51, 0, 8, 0, 0, 0, 36,
+	52, 0, 10, 0, 0, 20, 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, 39, 0, 0, 0,
+	68, 0, 67, 0, 0, 0, 0,
+	71, 15, 19, 0, 0, 0, 0,
+	72, 14, 29, 0, 28, 0, 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, 22, 0, 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, 36, 0, 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
diff -puN /dev/null drivers/char/speakup/speakupmap.map
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakupmap.map	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,91 @@
+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
+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
diff -puN /dev/null drivers/char/speakup/speakup_sftsyn.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_sftsyn.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,175 @@
+/* speakup_sftsynth.c - speakup driver to register and make available
+ * a user space device for software synthesizers.  written by: Kirk
+ * Reiser <kirk@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 <asm/semaphore.h>
+#include <linux/miscdevice.h>   /* for misc_register, and SYNTH_MINOR */
+#include <linux/poll.h>  // for poll_wait()
+#include "spk_priv.h"
+
+#define MY_SYNTH synth_sftsyn
+#define SOFTSYNTH_MINOR 26  // might as well give it one more than /dev/synth
+#define PROCSPEECH 0x0d
+#define CLEAR_SYNTH 0x18
+
+static struct miscdevice synth_device;
+static int misc_registered = 0;
+static int dev_opened = 0;
+static struct semaphore sem;
+DECLARE_WAIT_QUEUE_HEAD ( wait_on_output );
+
+
+static int softsynth_open (struct inode *inode, struct file *fp)
+{
+        if (dev_opened) return -EBUSY;
+	if ((fp->f_flags && O_ACCMODE) != O_RDONLY ) return -EPERM;
+	sema_init( &sem, 1 );
+	dev_opened++;
+        return 0;
+}
+
+static int softsynth_close (struct inode *inode, struct file *fp)
+{
+        fp->f_op = NULL;
+	dev_opened = 0;
+	return 0;
+}
+
+static ssize_t softsynth_read (struct file *fp, char *buf, size_t count, loff_t *pos)
+{
+int chars_sent=0;
+
+        if (down_interruptible( &sem )) return -ERESTARTSYS;
+        while (synth_buff_in == synth_buff_out) {
+	  up ( &sem );
+	  if (fp->f_flags & O_NONBLOCK)
+	    return -EAGAIN;
+	  if (wait_event_interruptible( wait_on_output, (synth_buff_in > synth_buff_out)))
+	    return -ERESTARTSYS;
+	  if (down_interruptible( &sem )) return -ERESTARTSYS;
+	}
+
+	chars_sent = (count > synth_buff_in-synth_buff_out)
+	  ? synth_buff_in-synth_buff_out : count;
+	if (copy_to_user(buf, (char *) synth_buff_out, chars_sent)) {
+	  up ( &sem);
+	  return -EFAULT;
+	}
+	synth_buff_out += chars_sent;
+	*pos += chars_sent;
+	if (synth_buff_out >= synth_buff_in) {
+	  synth_done();
+	  *pos = 0;
+	}
+	up ( &sem );
+	return chars_sent;
+}
+
+static unsigned int softsynth_poll (struct file *fp, struct poll_table_struct *wait)
+{
+        poll_wait(fp, &wait_on_output, wait);
+
+	if (synth_buff_out < synth_buff_in)
+	  return (POLLIN | POLLRDNORM);
+	return 0;
+}
+
+static void
+softsynth_flush( void )
+{
+	synth_write( "\x18", 1 );
+}
+
+static struct file_operations softsynth_fops = {
+        poll:softsynth_poll,
+        read:softsynth_read,
+        open:softsynth_open,
+        release:softsynth_close,
+};
+
+
+static int
+softsynth_probe( void )
+{
+
+        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 void
+softsynth_start ( void )
+{
+        wake_up_interruptible ( &wait_on_output );
+}
+
+static int
+softsynth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	return 0;
+}
+
+static const char init_string[] = "\01@\x01\x31y\n";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x01+3p" },
+	{ CAPS_STOP, "\x01-3p" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x01%ds", 5, 0, 9, 0, 0, 0 },
+	{ PITCH, "\x01%dp", 5, 0, 9, 0, 0, 0 },
+	{ VOL, "\x01%dv", 5, 0, 9, 0, 0, 0 },
+	{ TONE, "\x01%dx", 1, 0, 2, 0, 0, 0 },
+	{ PUNCT, "\x01%db", 7, 0, 15, 0, 0, 0 },
+	{ VOICE, "\x01%do", 0, 0, 7, 0, 0, 0 },
+	{ FREQ, "\x01%df", 5, 0, 9, 0, 0, 0 },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_sftsyn = { "sftsyn", "0.3", "software synth",
+	init_string, 0, 0, 0, 0, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, softsynth_probe, softsynth_release, NULL,
+	NULL, softsynth_start, softsynth_flush, softsynth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_spkout.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_spkout.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,188 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_spkout
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r'
+
+static int wait_for_xmitr(void)
+{
+	static int timeouts = 0;	/* sequential number of timeouts */
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ((synth_alive) && (timeouts >= NUM_DISABLE_TIMEOUTS)) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do {
+		check = inb(synth_port_tts + UART_LSR);
+		if (--tmout == 0) {
+			pr_warn("SpeakOut:  timed out\n");
+			timeouts++;
+			return 0;
+		}
+	} while ((check & BOTH_EMPTY) != BOTH_EMPTY);
+	tmout = SPK_XMITR_TIMEOUT;
+	do {
+		check = inb(synth_port_tts + UART_MSR);
+				if (--tmout == 0) {
+					timeouts++;
+					return 0;
+				}
+	} while ((check & UART_MSR_CTS) != UART_MSR_CTS);
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out(const char ch)
+{
+	if (synth_alive && wait_for_xmitr()) {
+		outb(ch, synth_port_tts);
+		return 1;
+	}
+	return 0;
+}
+
+static unsigned char spk_serial_in(void)
+{
+	int c, lsr, tmout = SPK_SERIAL_TIMEOUT;
+	do {
+		lsr = inb(synth_port_tts + UART_LSR);
+		if (--tmout == 0) return 0xff;
+	} while (!(lsr & UART_LSR_DR));
+	c = inb(synth_port_tts + UART_RX);
+	return (unsigned char) c;
+}
+
+static void do_catch_up(unsigned long data)
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+synth_stop_timer();
+	while (synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if (ch == 0x0a) ch = PROCSPEECH;
+		if (!spk_serial_out(ch )) {
+			synth_delay(synth_full_time);
+			return;
+		}
+		synth_buff_out++;
+		if (jiffies >= jiff_max && ch == SPACE ) {
+			spk_serial_out(PROCSPEECH);
+			synth_delay(synth_delay_time);
+			return;
+		}
+	}
+spk_serial_out(PROCSPEECH);
+	synth_done( );
+}
+
+static char *synth_immediate (char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if (ch == 0x0a) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+          outb( ch, synth_port_tts );
+        else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush(void)
+{
+	while ((inb(synth_port_tts + UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY);
+	outb(SYNTH_CLEAR, synth_port_tts);
+}
+
+static int serprobe(int index)
+{
+	struct serial_state *ser = spk_serial_init(index);
+	if ( ser == NULL ) return -1;
+	/* ignore any error results, if port was forced */
+	if (synth_port_forced) return 0;
+	/* check for speak out now... */
+	synth_immediate( "\x05[\x0f\r" );
+	mdelay( 10 ); //failed with no delay
+	if (spk_serial_in() == 0x0f) return 0;
+	synth_release_region(ser->port,8);
+			  synth_alive = 0;
+			  return -1;
+}
+
+static int synth_probe(void)
+{
+int i=0, failed=0;
+	pr_info("Probing for %s.\n", synth->long_name);
+	for (i=SPK_LO_TTY; i <= SPK_HI_TTY; i++) {
+	  if (( failed = serprobe( i )) == 0 ) break; /* found it */
+        }
+        if ( failed ) {
+		pr_info("%s Out:  not found\n", synth->long_name);
+		return -ENODEV;
+	}
+	pr_info("%s Out:  %03x-%03x, Driver version %s,\n", synth->long_name,
+   synth_port_tts, synth_port_tts + 7, synth->version);
+	return 0;
+}
+
+static int synth_is_alive(void)
+{
+	if (synth_alive) return 1;
+	if (wait_for_xmitr() > 0) { /* restart */
+		synth_alive = 1;
+		synth_write_string(synth->init );
+		return 2;
+	} else pr_warn("%s Out: can't restart synth\n", synth->long_name);
+	return 0;
+}
+
+static const char init_string[] = "\005W1\005I2\005C3";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x05P+" },
+	{ CAPS_STOP, "\x05P-" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x05R%d", 7, 0, 9, 0, 0, 0 },
+	{ PITCH, "\x05P%d", 3, 0, 9, 0, 0, 0 },
+	{ VOL, "\x05V%d", 9, 0, 9, 0, 0, 0 },
+	{ TONE, "\x05T%c", 8, 0, 25, 65, 0, 0 },
+	{ PUNCT, "\x05M%c", 0, 0, 3, 0, 0, "nsma" },
+	V_LAST_NUM
+};
+
+struct spk_synth synth_spkout = {"spkout", "1.1", "Speakout",
+	 init_string, 500, 50, 50, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/speakup_txprt.c
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/speakup_txprt.c	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,195 @@
+/*
+ * originially written by: Kirk Reiser <kirk@braille.uwo.ca>
+* this version considerably modified by David Borowski, david575@rogers.com
+
+		Copyright (C) 1998-99  Kirk Reiser.
+		Copyright (C) 2003 David Borowski.
+
+		This program is free software; you can redistribute it and/or modify
+		it under the terms of the GNU General Public License as published by
+		the Free Software Foundation; either version 2 of the License, or
+		(at your option) any later version.
+
+		This program is distributed in the hope that it will be useful,
+		but WITHOUT ANY WARRANTY; without even the implied warranty of
+		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+		GNU General Public License for more details.
+
+		You should have received a copy of the GNU General Public License
+		along with this program; if not, write to the Free Software
+		Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ * this code is specificly written as a driver for the speakup screenreview
+ * package and is not a general device driver.
+		*/
+#include "spk_priv.h"
+#include "serialio.h"
+
+#define MY_SYNTH synth_txprt
+#define DRV_VERSION "1.2"
+#define SYNTH_CLEAR 0x18
+#define PROCSPEECH '\r' /* process speech char */
+
+static int timeouts = 0;	/* sequential number of timeouts */
+
+static int wait_for_xmitr( void )
+{
+	int check, tmout = SPK_XMITR_TIMEOUT;
+	if ( ( synth_alive ) && ( timeouts >= NUM_DISABLE_TIMEOUTS ) ) {
+		synth_alive = 0;
+		timeouts = 0;
+		return 0;
+	}
+	do {
+		check = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) {
+			pr_warn( "TXPRT:  timed out\n" );
+			timeouts++;
+			return 0;
+		}
+	} while ( ( check & BOTH_EMPTY ) != BOTH_EMPTY );
+	tmout = SPK_XMITR_TIMEOUT;
+	do {
+		check = inb( synth_port_tts + UART_MSR );
+				if ( --tmout == 0 ) {
+					timeouts++;
+					return 0;
+				}
+	} while ( ( check & UART_MSR_CTS ) != UART_MSR_CTS );
+	timeouts = 0;
+	return 1;
+}
+
+static inline int spk_serial_out( const char ch )
+{
+	if ( synth_alive && wait_for_xmitr( ) ) {
+		outb( ch, synth_port_tts );
+		return 1;
+	}
+	return 0;
+}
+
+static unsigned char spk_serial_in( void )
+{
+	int c, lsr, tmout = SPK_SERIAL_TIMEOUT;
+	do {
+		lsr = inb( synth_port_tts + UART_LSR );
+		if ( --tmout == 0 ) return 0xff;
+	} while ( !( lsr & UART_LSR_DR ) );
+	c = inb( synth_port_tts + UART_RX );
+	return ( unsigned char ) c;
+}
+
+static void do_catch_up( unsigned long data )
+{
+	unsigned long jiff_max = jiffies+synth_jiffy_delta;
+	u_char ch;
+
+	synth_stop_timer( );
+	while ( synth_buff_out < synth_buff_in ) {
+		ch = *synth_buff_out;
+		if ( ch == '\n' ) ch = PROCSPEECH;
+		if ( !spk_serial_out( ch ) ) {
+			synth_delay( synth_full_time );
+			return;
+		}
+		synth_buff_out++;
+		if ( jiffies >= jiff_max && ch == ' ' ) {
+			spk_serial_out( PROCSPEECH );
+			synth_delay( synth_delay_time );
+			return;
+		}
+	}
+	spk_serial_out( PROCSPEECH );
+	synth_done( );
+}
+
+static char *synth_immediate ( char *buf )
+{
+	u_char ch;
+	while ( ( ch = *buf ) ) {
+	if ( ch == 0x0a ) ch = PROCSPEECH;
+        if ( wait_for_xmitr( ) )
+	  outb( ch, synth_port_tts );
+	else return buf;
+	buf++;
+	}
+	return 0;
+}
+
+static void synth_flush ( void )
+{
+	spk_serial_out ( SYNTH_CLEAR );
+}
+
+static int serprobe( int index )
+{
+	u_char test=0;
+	struct serial_state *ser = spk_serial_init( index );
+	if ( ser == NULL ) return -1;
+	if ( synth_port_forced ) return 0;
+	/* check for txprt now... */
+	if (synth_immediate( "\x05$" ))
+	  pr_warn("synth_immediate could not unload\n");
+	if (synth_immediate( "\x05Ik" ))
+	  pr_warn("synth_immediate could not unload again\n");
+	if (synth_immediate( "\x05Q\r" ))
+	  pr_warn("synth_immediate could not unload a third time\n");
+	if ( ( test = spk_serial_in( ) ) == 'k' ) return 0;
+	else pr_warn( "synth returned %x on port %03lx\n", test, ser->port );
+	synth_release_region( ser->port,8 );
+	timeouts = synth_alive = 0;
+			  return -1;
+}
+
+static int synth_probe( void )
+{
+	int i, failed=0;
+	pr_info( "Probing for %s.\n", synth->long_name );
+	for ( i=SPK_LO_TTY; i <= SPK_HI_TTY; i++ ) {
+		if (( failed = serprobe( i )) == 0 ) break; /* found it */
+	}
+	if ( failed ) {
+		pr_info( "%s:  not found\n", synth->long_name );
+		return -ENODEV;
+	}
+	pr_info( "%s: %03x-%03x..\n", synth->long_name, (int) synth_port_tts, (int) synth_port_tts+7 );
+	pr_info( "%s: driver version %s.\n",  synth->long_name, synth->version);
+	return 0;
+}
+
+static int synth_is_alive( void )
+{
+	if ( synth_alive ) return 1;
+	if ( wait_for_xmitr( ) > 0 ) { /* restart */
+		synth_alive = 1;
+		synth_write_string( synth->init );
+		return 2;
+	}
+	pr_warn( "%s: can't restart synth\n", synth->long_name );
+	return 0;
+}
+
+static const char init_string[] = "\x05N1";
+
+static string_var stringvars[] = {
+	{ CAPS_START, "\x05P8" },
+	{ CAPS_STOP, "\x05P5" },
+	V_LAST_STRING
+};
+static num_var numvars[] = {
+	{ RATE, "\x05R%d", 5, 0, 9, 0, 0, 0 },
+	{ PITCH, "\x05P%d", 5, 0, 9, 0, 0, 0 },
+	{ VOL, "\x05V%d", 5, 0, 9, 0, 0, 0 },
+	{ TONE, "\x05T%c", 12, 0, 25, 61, 0, 0 },
+	V_LAST_NUM
+	 };
+
+struct spk_synth synth_txprt = {"txprt", DRV_VERSION, "Transport",
+	init_string, 500, 50, 50, 5000, 0, 0, SYNTH_CHECK,
+	stringvars, numvars, synth_probe, spk_serial_release, synth_immediate,
+	do_catch_up, NULL, synth_flush, synth_is_alive, NULL};
+
+#ifdef MODULE
+#include "mod_code.c"
+#endif
diff -puN /dev/null drivers/char/speakup/spk_con_module.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/spk_con_module.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,43 @@
+/* written bby 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
+*/
+
+/* included by ../console.c for speakup modularization */
+
+static spk_con_func addr_spk_allocate = NULL;
+static spk_con_func addr_spk_bs = NULL;
+static spk_write_func addr_spk_con_write = NULL;
+static spk_con_func addr_spk_con_update = NULL;
+
+#define speakup_allocate(c) if (addr_spk_allocate) (*addr_spk_allocate)(c)
+#define speakup_bs(c) if (addr_spk_bs) (*addr_spk_bs)(c)
+#define speakup_con_write(c,s,l) if (addr_spk_con_write) (*addr_spk_con_write)(c,s,l)
+#define speakup_con_update(c) if (addr_spk_con_update) (*addr_spk_con_update)(c)
+
+extern spk_key_func addr_spk_key;
+
+void speakup_set_addresses( spk_con_func allocate, spk_con_func bs,
+	spk_write_func con_write, spk_con_func con_update, spk_key_func key )
+{
+	addr_spk_allocate = allocate;
+	addr_spk_bs = bs;
+	addr_spk_con_write = con_write;
+	addr_spk_con_update = con_update;
+	addr_spk_key = key;
+}
+
+EXPORT_SYMBOL(speakup_set_addresses);
diff -puN /dev/null drivers/char/speakup/spk_priv.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/spk_priv.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,258 @@
+/* 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
+
+#define KERNEL
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <asm/io.h>		/* for inb_p, outb_p, inb, outb, etc... */
+#include <linux/delay.h>
+#include <linux/wait.h>		/* for wait_queue */
+#include <linux/init.h> /* for __init */
+#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+#include <linux/speakup.h>
+#include "keyinfo.h"
+
+#define SHIFT_TBL_SIZE 64
+/* 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 V_LAST_STRING { -1, 0 }
+#define V_LAST_NUM { -1, 0, 0, 0, 0, 0, 0, 0 }
+#define TOGGLE_0 0, 0, 0, 1, 0, 0, 0
+#define TOGGLE_1 0, 1, 0, 1, 0, 0, 0
+#define MAXVARLEN 15
+#define TAB 0x9
+#define SPACE 0x20
+#define CAP_A 'A'
+#define CAP_Z 'Z'
+#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
+#define IS_WDLM( x ) ( spk_chartab[( ( u_char )x )]&B_WDLM )
+#define IS_CHAR( x, type ) ( spk_chartab[( ( u_char )x )]&type )
+#define SET_DEFAULT -4
+#define E_RANGE -3
+#define E_TOOLONG -2
+#define E_UNDEF -1
+enum { VAR_NUM = 0, VAR_TIME, VAR_STRING, VAR_PROC };
+enum { E_DEFAULT = 0, E_SET, E_INC, E_DEC };
+
+#define PROC_READ_PROTOTYPE char *page, char **start, off_t off, \
+			int count, int *eof, void *data
+#define PROC_WRITE_PROTOTYPE struct file *file, const char *buffer, \
+		u_long count, void *data
+
+#ifndef MIN
+#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
+#endif
+
+typedef int (*special_func)( struct vc_data *vc, u_char type, u_char ch, u_short key );
+typedef struct st_var_header var_header;
+typedef struct st_num_var num_var;
+typedef struct st_string_var string_var;
+typedef struct st_proc_var proc_var;
+
+struct st_var_header {
+	char *name;
+	short var_id, var_type, proc_mode;
+	void *proc_entry;
+	void *p_val; /* ptr to programs variable to store value */
+	void *data; /* ptr to the vars data */
+};
+
+/* next are data for different var types */
+struct st_num_var {
+	short var_id;
+	char *synth_fmt;
+	short default_val, low, high;
+	short offset, multiplier; /* for fiddling rates etc. */
+	char *out_str; /* if synth needs char representation of number */
+	short value; /* current value */
+};
+struct st_string_var {
+	short var_id;
+	char *default_val;
+};
+struct st_proc_var {
+	short var_id;
+	int ( *read_proc )( PROC_READ_PROTOTYPE );
+	int ( *write_proc )( PROC_WRITE_PROTOTYPE );
+	short value;
+};
+
+typedef struct st_bits_data bits_data;
+struct st_bits_data { /* punc, repeats, word delim bits */
+	char *name;
+	char *value;
+	short mask;
+};
+
+extern var_header *var_ptrs[MAXVARS];
+extern proc_var spk_proc_vars[];
+char *xlate( char * );
+char *speakup_s2i( char *, short * );
+int speakup_register_var( num_var *var );
+void speakup_unregister_var( short var_id );
+extern var_header *get_var_header( short var_id );
+extern int set_num_var( short val, var_header *var, int how );
+
+/* let's develop a structure for keeping our goodies in. */
+typedef struct st_spk_t spk_t;
+#define spk_size (sizeof( spk_t))
+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;
+};
+
+/* 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
+#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 */
+
+struct spk_synth {
+	const char *name;
+	const char *version;
+	const char *long_name;
+	const char *init;
+	short delay, trigger, jiffies, full, flush_wait, flags;
+	const int checkval; /* for validating a proper synth module */
+	string_var *string_vars;
+	num_var *num_vars;
+	int ( *probe )( void );
+	void ( *release )( void );
+	char *( *synth_immediate )( char *buff );
+	void ( *catch_up )( u_long data );
+	void ( *start )( void );
+	void ( *flush )( void );
+	int ( *is_alive )( void );
+	int ( *synth_adjust )( var_header *var );
+};
+
+extern struct spk_synth *synth;
+int synth_request_region( u_long, u_long );
+int synth_release_region( u_long, u_long );
+void spk_serial_release( void );
+extern int synth_port_tts, synth_port_forced;
+extern volatile int synth_timer_active;
+#define declare_timer( name ) struct timer_list name;
+#if (LINUX_VERSION_CODE >= 132419)
+#define start_timer( name ) if ( ! name.entry.prev ) add_timer ( & name )
+#define stop_timer( name ) del_timer ( & name ); name.entry.prev = NULL
+#else
+#define start_timer( name ) if ( ! name.list.prev ) add_timer ( & name )
+#define stop_timer( name ) del_timer ( & name )
+#endif
+#define declare_sleeper( name ) wait_queue_head_t name
+#define init_sleeper( name ) 	init_waitqueue_head ( &name )
+extern declare_sleeper( synth_sleeping_list );
+extern declare_timer( synth_timer );
+extern char str_caps_start[], str_caps_stop[];
+extern short no_intr, say_ctrl, say_word_ctl, punc_level;
+extern short reading_punc, attrib_bleep, bleeps;
+extern short bleep_time, bell_pos;
+extern short spell_delay, key_echo, punc_mask;
+extern short synth_jiffy_delta, synth_delay_time;
+extern short synth_trigger_time, synth_full_time;
+extern short cursor_timeout, pitch_shift, synth_flags;
+extern int synth_alive;
+extern u_char synth_buffer[];  /* guess what this is for! */
+extern u_char *buffer_highwater;
+extern volatile u_char *synth_buff_in, *synth_buff_out;
+int synth_init( char *name );
+int do_synth_init( struct spk_synth *in_synth );
+void synth_release( void );
+void synth_add( struct spk_synth *in_synth );
+void synth_remove( struct spk_synth *in_synth );
+struct serial_state * spk_serial_init( int index );
+void synth_delay( int ms );
+void synth_stop_timer( void );
+int synth_done( void );
+void do_flush( void );
+void synth_buffer_add( char ch );
+void synth_write( const char *buf, size_t count );
+void synth_write_string( const char *buf );
+void synth_write_msg( const char *buf );
+void speakup_register_devsynth ( void );
+
+#ifndef pr_info
+#define pr_info(fmt,arg...) printk(KERN_INFO fmt,##arg)
+#endif
+#ifndef pr_warn
+#define pr_warn(fmt,arg...) printk(KERN_WARNING fmt,##arg)
+#endif
+
+#endif
diff -puN /dev/null drivers/char/speakup/synthlist.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/drivers/char/speakup/synthlist.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,54 @@
+/* this is included two times */
+#if defined(PASS2)
+/* table of built in synths */
+#define SYNTH_DECL(who) &synth_##who,
+#define  CFG_TEST(name) (name)
+#else
+/* declare extern built in synths */
+#define SYNTH_DECL(who) extern struct spk_synth synth_##who;
+#define PASS2
+#define  CFG_TEST(name) (name)
+#endif
+
+#if CFG_TEST(CONFIG_SPEAKUP_ACNTPC)
+SYNTH_DECL(acntpc)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_ACNTSA)
+SYNTH_DECL(acntsa)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_APOLLO)
+SYNTH_DECL(apollo)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_AUDPTR)
+SYNTH_DECL(audptr)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_BNS)
+SYNTH_DECL(bns)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_DECEXT)
+SYNTH_DECL(decext)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_DECTLK)
+SYNTH_DECL(dectlk)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_DTLK)
+SYNTH_DECL(dtlk)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_KEYPC)
+SYNTH_DECL(keypc)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_LTLK)
+SYNTH_DECL(ltlk)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_SFTSYN)
+SYNTH_DECL(sftsyn)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_SPKOUT)
+SYNTH_DECL(spkout)
+#endif
+#if CFG_TEST(CONFIG_SPEAKUP_TXPRT)
+SYNTH_DECL(txprt)
+#endif
+
+#undef SYNTH_DECL
+#undef CFG_TEST
diff -puN drivers/char/vt.c~gregkh-driver-speakup-core drivers/char/vt.c
--- devel/drivers/char/vt.c~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/char/vt.c	2005-09-07 19:39:50.000000000 -0700
@@ -98,6 +98,10 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
+#include <linux/speakup.h>
+#ifdef CONFIG_SPEAKUP_MODULE
+#include "speakup/spk_con_module.h"
+#endif
 
 const struct consw *conswitchp;
 
@@ -725,6 +729,7 @@ int vc_allocate(unsigned int currcons)	/
 	    }
 	    vc->vc_kmalloced = 1;
 	    vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
+	    speakup_allocate(vc);
 	}
 	return 0;
 }
@@ -952,6 +957,7 @@ static void lf(struct vc_data *vc)
 		vc->vc_pos += vc->vc_size_row;
 	}
 	vc->vc_need_wrap = 0;
+	speakup_con_write(vc, "\n",1);
 }
 
 static void ri(struct vc_data *vc)
@@ -980,6 +986,7 @@ static inline void bs(struct vc_data *vc
 		vc->vc_pos -= 2;
 		vc->vc_x--;
 		vc->vc_need_wrap = 0;
+		speakup_bs(vc);
 	}
 }
 
@@ -1517,6 +1524,7 @@ static void do_con_trol(struct tty_struc
 				break;
 		}
 		vc->vc_pos += (vc->vc_x << 1);
+		speakup_con_write(vc, " ", 1);
 		return;
 	case 10: case 11: case 12:
 		lf(vc);
@@ -2047,6 +2055,7 @@ static int do_con_write(struct tty_struc
 			}
 			if (vc->vc_decim)
 				insert_char(vc, 1);
+			speakup_con_write(vc, (char *) &tc, 1);
 			scr_writew(himask ?
 				     ((vc->vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
 				     (vc->vc_attr << 8) + tc,
@@ -2072,6 +2081,7 @@ static int do_con_write(struct tty_struc
 	release_console_sem();
 
 out:
+	speakup_con_update(vc);
 	return n;
 #undef FLUSH
 }
@@ -2097,6 +2107,7 @@ static void console_callback(void *ignor
 			/* we only changed when the console had already
 			   been allocated - a new console is not created
 			   in an interrupt routine */
+			speakup_con_update(vc_cons[want_console].d);
 		}
 		want_console = -1;
 	}
@@ -2115,6 +2126,7 @@ static void console_callback(void *ignor
 		do_blank_screen(0);
 		blank_timer_expired = 0;
 	}
+	speakup_con_update(vc_cons[fg_console].d);
 
 	release_console_sem();
 }
@@ -2172,6 +2184,7 @@ static void vt_console_print(struct cons
 
 	/* Contrived structure to try to emulate original need_wrap behaviour
 	 * Problems caused when we have need_wrap set on '\n' character */
+	speakup_con_write(vc, b, count);
 	while (count--) {
 		c = *b++;
 		if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
@@ -2216,6 +2229,7 @@ static void vt_console_print(struct cons
 		}
 	}
 	set_cursor(vc);
+	speakup_con_update(vc);
 
 quit:
 	clear_bit(0, &printing);
@@ -2561,6 +2575,7 @@ static int __init con_init(void)
 	master_display_fg = vc = vc_cons[currcons].d;
 	set_origin(vc);
 	save_screen(vc);
+	speakup_init(vc);
 	gotoxy(vc, vc->vc_x, vc->vc_y);
 	csi_J(vc, 0);
 	update_screen(vc);
@@ -3253,3 +3268,4 @@ EXPORT_SYMBOL(vc_cons);
 EXPORT_SYMBOL(take_over_console);
 EXPORT_SYMBOL(give_up_console);
 #endif
+EXPORT_SYMBOL(screen_glyph);
diff -puN drivers/Kconfig~gregkh-driver-speakup-core drivers/Kconfig
--- devel/drivers/Kconfig~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/Kconfig	2005-09-07 19:39:50.000000000 -0700
@@ -54,6 +54,8 @@ source "drivers/media/Kconfig"
 
 source "drivers/video/Kconfig"
 
+source "drivers/char/speakup/Kconfig"
+
 source "sound/Kconfig"
 
 source "drivers/usb/Kconfig"
diff -puN drivers/Makefile~gregkh-driver-speakup-core drivers/Makefile
--- devel/drivers/Makefile~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/drivers/Makefile	2005-09-07 19:39:50.000000000 -0700
@@ -1,4 +1,3 @@
-#
 # Makefile for the Linux kernel device drivers.
 #
 # 15 Sep 2000, Christoph Hellwig <hch@infradead.org>
@@ -25,6 +24,8 @@ obj-$(CONFIG_FB_INTEL)          += video
 # serial drivers start registering their serio ports
 obj-$(CONFIG_SERIO)		+= input/serio/
 obj-y				+= serial/
+# load keyboard early so speakup can be quieted
+obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_PARPORT)		+= parport/
 obj-y				+= base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)		+= nubus/
@@ -48,7 +49,6 @@ obj-$(CONFIG_TC)		+= tc/
 obj-$(CONFIG_USB)		+= usb/
 obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
-obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
diff -puN include/linux/keyboard.h~gregkh-driver-speakup-core include/linux/keyboard.h
--- devel/include/linux/keyboard.h~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/include/linux/keyboard.h	2005-09-07 19:39:50.000000000 -0700
@@ -44,6 +44,7 @@ extern unsigned short plain_map[NR_KEYS]
 #define KT_ASCII	9
 #define KT_LOCK		10
 #define KT_SLOCK	12
+#define KT_SPKUP       	14
 
 #define K(t,v)		(((t)<<8)|(v))
 #define KTYP(x)		((x) >> 8)
@@ -426,6 +427,7 @@ extern unsigned short plain_map[NR_KEYS]
 #define K_CTRLR_SLOCK	K(KT_SLOCK,KG_CTRLR)
 
 #define NR_LOCK		8
+#define NR_SPKUP       0x45
 
 #define MAX_DIACR	256
 #endif
diff -puN /dev/null include/linux/speakup.h
--- /dev/null	2003-09-15 06:40:47.000000000 -0700
+++ devel-akpm/include/linux/speakup.h	2005-09-07 19:39:50.000000000 -0700
@@ -0,0 +1,33 @@
+#ifndef __SPEAKUP_H
+#define __SPEAKUP_H
+
+#include <linux/version.h>
+
+struct kbd_struct;
+struct vc_data;
+
+/* how about some prototypes! */
+extern int do_spk_ioctl(int,unsigned char *data,int,void *);
+
+#if defined(CONFIG_SPEAKUP)
+extern void speakup_init(struct vc_data *);
+extern void speakup_allocate(struct vc_data *);
+extern void speakup_bs(struct vc_data *);
+extern void speakup_con_write(struct vc_data *, const char *, int);
+extern void speakup_con_update(struct vc_data *);
+extern int speakup_key(struct vc_data*, int, int, u_short, int, struct pt_regs *);
+#elif defined(CONFIG_SPEAKUP_MODULE)
+typedef void (*spk_con_func)(struct vc_data * );
+typedef void (*spk_write_func)(struct vc_data *, const char *, int);
+typedef int (*spk_key_func)(struct vc_data*, int, int, u_short, int, struct pt_regs *);
+extern void spk_set_addresses( spk_con_func allocate, spk_con_func bs,
+	spk_write_func con_write, spk_con_func con_update, spk_key_func key );
+static inline void speakup_init(struct vc_data *vc) { }
+#else
+static inline void speakup_allocate(struct vc_data *vc) { }
+static inline void speakup_bs(struct vc_data *vc) { }
+static inline void speakup_con_write(struct vc_data *vc, const char *str, int len) { }
+static inline void speakup_con_update(struct vc_data *vc) { }
+static inline void speakup_init(struct vc_data *vc) { }
+#endif
+#endif
diff -puN MAINTAINERS~gregkh-driver-speakup-core MAINTAINERS
--- devel/MAINTAINERS~gregkh-driver-speakup-core	2005-09-07 19:39:50.000000000 -0700
+++ devel-akpm/MAINTAINERS	2005-09-07 19:39:50.000000000 -0700
@@ -2243,6 +2243,13 @@ M:	wli@holomorphy.com
 L:	sparclinux@vger.kernel.org
 S:	Maintained
 
+SPEAKUP Console speech output
+P: Kirk Reiser
+M: kirk@braille.uwo.ca
+L: speakup@braille.uwo.ca
+W: http://www.linux-speakup.org
+S: Maintained
+
 SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER
 P:	Roger Wolff
 M:	R.E.Wolff@BitWizard.nl
_