diff --exclude .depend --exclude .hdepend -ur kernel-8.0/arch/mips/config.in kernel-8.0-w1/arch/mips/config.in
--- kernel-8.0/arch/mips/config.in	Thu Nov 15 21:51:59 2001
+++ kernel-8.0-w1/arch/mips/config.in	Sun Sep 22 12:12:05 2002
@@ -713,6 +713,7 @@
   if [ "$CONFIG_CPU_VR41XX" = "y" -a "$CONFIG_AGENDA_VR3" = "y" ]; then
     bool 'Agenda A/D interface support' CONFIG_ADIF
   fi
+  tristate 'Ericsson Chatboard support' CONFIG_CHATBOARD
 
   bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS
   if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
diff --exclude .depend --exclude .hdepend -ur kernel-8.0/drivers/char/Config.in kernel-8.0-w1/drivers/char/Config.in
--- kernel-8.0/drivers/char/Config.in	Thu Nov 15 21:52:21 2001
+++ kernel-8.0-w1/drivers/char/Config.in	Sun Sep 22 12:08:52 2002
@@ -191,4 +191,6 @@
 if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
    source drivers/char/pcmcia/Config.in
 fi
+
+tristate 'Ericsson Chatboard support' CONFIG_CHATBOARD
 endmenu
diff --exclude .depend --exclude .hdepend -ur kernel-8.0/drivers/char/Makefile kernel-8.0-w1/drivers/char/Makefile
--- kernel-8.0/drivers/char/Makefile	Thu Nov 15 21:52:17 2001
+++ kernel-8.0-w1/drivers/char/Makefile	Sun Sep 22 12:05:19 2002
@@ -153,6 +153,7 @@
 obj-$(CONFIG_SX) += sx.o generic_serial.o
 obj-$(CONFIG_RIO) += rio/rio.o generic_serial.o
 obj-$(CONFIG_SH_SCI) += sh-sci.o generic_serial.o
+obj-$(CONFIG_CHATBOARD) += chatboard.o
 
 ifeq ($(CONFIG_RIO),y)
   SUB_DIRS += rio
diff --exclude .depend --exclude .hdepend -ur kernel-8.0/drivers/char/chatboard.c kernel-8.0-w1/drivers/char/chatboard.c
--- kernel-8.0-w1/drivers/char/chatboard.c.orig	Mon Sep 23 20:15:19 2002
+++ kernel-8.0-w1/drivers/char/chatboard.c	Tue Oct  1 21:51:48 2002
@@ -0,0 +1,400 @@
+/* chatboard.c, (c) 2002 Milan Pikula <www@terminus.sk>
+ *
+ * Linux driver for Ericsson Chatboard.
+ *
+ * This driver works as a line discipline, which intercepts keys
+ * at the serial port. There are 2 modes supported:
+ * direct (most scancodes correspond to AT*EKSE codes)
+ * and PC keyboard emulation.
+ *
+ * This is a free software with ABSOLUTELY NO WARRANTY.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <asm/termios.h>
+#include <linux/tty_ldisc.h>
+#include <linux/slab.h>
+#include <linux/kbd_ll.h>
+#include <linux/init.h>
+
+/* steal a ldisc number ;) */
+#define N_CHATBOARD N_SMSBLOCK
+#define VERSION "1.1"
+
+/* isn't it a stupid design to allow applications to see
+ * raw scancodes, before keytables translation?
+ *
+ * Try to emulate PC keyboard to have less problems.
+ */
+#define PC_SCANCODES
+
+#ifdef PC_SCANCODES
+#define SHIFT	0x100	/* press SHIFT with key */
+#define CTRL	0x200	/* press CTRL with key */
+#define ALT	0x400	/* press ALT with key */
+#define SH_SPAC	0x800	/* emulate shift-space mode of chatboard */
+#define S SHIFT
+#define C CTRL
+#define A ALT
+unsigned int chat2scan[256] = {
+	11,2,3,4,5,6,7,8, 9,10,0,0,0,0,0,0,		/*   0 -  15 */
+	82,79,80,81,75,76,77,71, 72,73,0,0,0,0,0,0,		/*  16 -  31 */
+	S|11,S|2,S|3,S|4,S|5,S|6,S|53,S|8, S|9,S|10,0,0,0,0,0,0,		/*  32 -  47 */
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,		/*  48 -  63 */
+	0,30,48,46,32,18,33,34, 35,23,36,37,38,50,49,24,	/*  64 -  79 */
+	25,16,19,31,20,22,47,17, 45,21,44,57,52,0,0,0,		/*  80 -  95 */
+	0,0,53,S|12,40,41,43,S|40, 0,0,0,0,0,S|52,S|51,S|26,		/*  96 - 111 */
+	S|27,15,0,S|7,S|43,0,13,S|41, 12,S|39,S|13,0,51,0,0,0,		/* 112 - 127 */
+	0,S|30,S|48,S|46,S|32,S|18,S|33,S|34, S|35,S|23,S|36,S|37,S|38,S|50,S|49,S|24,	/* 128 - 143 */
+	S|25,S|16,S|19,S|31,S|20,S|22,S|47,S|17, S|45,S|21,S|44,0,51,0,0,0,		/* 144 - 159 */
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,27,26,0,		/* 160 - 175 */
+	0,S|15,0,0,0,0,0,41, 0,39,0,0,0,0,0,0,		/* 176 - 191 */
+	1,SH_SPAC,59,60,C,A,28,14, 105,106,0,0,0,0,0,0,		/* 192 - 207 */
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,		/* 208 - 223 */
+	0,SH_SPAC,61,62,C,A,96,111, 103,108,0,0,0,0,0,0,		/* 224 - 239 */
+	0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,		/* 240 - 255 */
+};
+#undef A
+#undef C
+#undef S
+#endif
+
+/* we define a state machine for input from chatboard */
+enum {
+	ST_MATCH,	/* match a string */
+	ST_NUMBER,	/* match a number and load it */
+	ST_NUMBER1,
+	ST_EOL,		/* wait for EOL */
+	ST_START,	/* send OK */
+	ST_WAIT,
+	ST_AT,
+	ST_ATE,
+	ST_EKSE,	/* AT*EKSE=<integer>  */
+	ST_EKSE1,
+	ST_CKPD,	/* AT+CKPD="<string>" */
+	ST_EAPP,	/* AT*EAPP=<integer>,<integer> */
+	ST_EAPP1,
+	ST_EAPP2,
+	ST_EAPP3,
+
+	ST_DEBUGNR
+
+};
+
+struct chb_s {
+/* input state machine */
+	int state;
+
+	/* used by ST_MATCH and ST_NUMBER */
+	char * expect;	/* what we expect */
+	int value;	/* or what value we read */
+	int new_state;	/* and where to go when all matched */
+
+/* output state machine */
+	int send_pos;
+
+/* keyboard state */
+	int modifiers;
+};
+#define CHB ((struct chb_s *)(tty->disc_data))
+
+/* helper data for output */
+#define OK "OK\r\n"
+#define OK_LEN 4
+
+/* this forwards the keys into kernel */
+void press(struct tty_struct * tty, int chatcode)
+{
+#ifdef PC_SCANCODES
+	int scan;
+
+	chatcode &= 255; /* safety */
+
+	if (CHB->modifiers & SH_SPAC) { /* handle 'fn' mode */
+		if (chatcode < 64)
+			chatcode ^= 16;
+		else /* if (chatcode < 224) */
+			chatcode ^= 32;
+	}
+
+	scan = chat2scan[chatcode];
+
+	if (scan & 0xff) /* for combined, ignore dead which we already have */
+		scan &= ~(CHB->modifiers);
+
+	/* need to press or release some dead keys? */
+	if (scan & CTRL)
+		handle_scancode(29, !(CHB->modifiers & CTRL));
+	if (scan & ALT)
+		handle_scancode(56, !(CHB->modifiers & ALT));
+	if (scan & SHIFT)
+		handle_scancode(42,  !(CHB->modifiers & SHIFT));
+
+	/* update dead key status */
+	CHB->modifiers ^= scan & ~0xff;
+
+	if (scan & 0xff) {
+		handle_scancode(scan /* & 0xff */, 1);
+		handle_scancode(scan /* & 0xff */, 0);
+		/* restore dead keys */
+		if (CHB->modifiers & SHIFT)
+			handle_scancode(42, 0);
+		if ((CHB->modifiers & ALT))
+			handle_scancode(56, 0);
+		if ((CHB->modifiers & CTRL))
+			handle_scancode(29, 0);
+		CHB->modifiers = 0;
+	}
+#else
+	// printk(KERN_INFO "PRESS: %d\n", chatcode);
+	handle_scancode(chatcode, 1);
+	handle_scancode(chatcode, 0);
+#endif
+
+}
+
+
+/* send some characters to the chatboard */
+static void ld_write(struct tty_struct * tty)
+{
+	if (CHB->send_pos == -1)
+		return;
+	CHB->send_pos += tty->driver.write(tty, 0, OK +
+			CHB->send_pos, OK_LEN - CHB->send_pos);
+	if (OK[CHB->send_pos] == 0)
+		CHB->send_pos = -1;
+	return;
+}
+
+/* initialize the state machine */
+static int ld_open(struct tty_struct * tty)
+{
+	MOD_INC_USE_COUNT;
+
+	if (CHB) {
+		MOD_DEC_USE_COUNT;
+		return -EEXIST;
+	}
+
+	CHB = (struct chb_s *)kmalloc(sizeof(struct chb_s), GFP_KERNEL);
+	if (CHB == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	printk(KERN_INFO "Opening Chatboard discipline\n");
+	CHB->state = ST_WAIT;
+	CHB->send_pos = 0;
+	CHB->modifiers = 0;
+	ld_write(tty); /* send first OK */
+	
+	return 0;
+
+}
+
+/* deallocate anything */
+static void ld_close(struct tty_struct * tty)
+{
+	kfree(CHB);
+	CHB = NULL;
+	printk(KERN_INFO "Closing Chatboard discipline\n");
+	MOD_DEC_USE_COUNT;
+}
+
+/* get a character from the keyboard */
+static void ld_receive(struct tty_struct * tty, const unsigned char * cp,
+		char * fp, int count)
+{
+#define NEXT_CHAR() do { cp++; if (fp) fp++; } while (--count && fp && *fp)
+
+	while (count) {
+		// printk("State:%d Char:%c Count:%d\n", CHB->state, *cp, count);
+		switch (CHB->state) {
+			/* eat the expect-string and move on */
+			case ST_MATCH:
+				if (*cp != *(CHB->expect)) {
+					CHB->state = ST_EOL;
+					break;
+				}
+				NEXT_CHAR(); CHB->expect++;
+				if (*(CHB->expect) == 0) /* all found */
+					CHB->state = CHB->new_state;
+				break;
+
+			/* read the number and move on */
+			case ST_NUMBER:
+				CHB->value = 0;
+				CHB->state = ST_NUMBER1;
+				/* fallthrough */
+			case ST_NUMBER1:
+				if ((*cp < '0') || (*cp > '9')) {
+					CHB->state = CHB->new_state;
+					break;
+				}
+				CHB->value = CHB->value * 10 + (int)(*cp - '0');
+				NEXT_CHAR();
+				break;
+
+			/* eat anything to EOL then send <OK> */
+			case ST_EOL:
+				if (*cp != '\r') {
+					NEXT_CHAR();
+					break;
+				}
+				NEXT_CHAR();
+
+			/* send OK and await next line */
+			case ST_START:
+				if (CHB->send_pos == -1)
+					CHB->send_pos = 0;
+				ld_write(tty);
+				CHB->state = ST_WAIT;
+				break;
+
+			case ST_WAIT:
+				CHB->expect = "AT"; CHB->new_state = ST_AT;
+				CHB->state = ST_MATCH;
+				break;
+
+			/* AT decoded; what next? */
+			case ST_AT:
+				if (*cp == '*') {
+					CHB->expect = "*E";
+					CHB->new_state = ST_ATE;
+					CHB->state = ST_MATCH;
+				} else if (*cp == '+') {
+					CHB->expect = "+CKPD=\"";
+					CHB->new_state = ST_CKPD;
+					CHB->state = ST_MATCH;
+				} else
+					CHB->state = ST_EOL;
+				break;
+			case ST_ATE:
+				if (*cp == 'K') {
+					CHB->expect = "KSE=";
+					CHB->new_state = ST_EKSE;
+					CHB->state = ST_MATCH;
+				} else if (*cp == 'A') {
+					CHB->expect = "APP=";
+					CHB->new_state = ST_EAPP;
+					CHB->state = ST_MATCH;
+				} else
+					CHB->state = ST_EOL;
+				break;
+
+			/* AT*EKSE */
+			case ST_EKSE:
+				CHB->state = ST_NUMBER;
+				CHB->new_state = ST_EKSE1;
+				break;
+			case ST_EKSE1:
+				press(tty, CHB->value);
+				CHB->state = ST_EOL;
+				break;
+
+			/* AT+CKPD */
+			case ST_CKPD:
+				if (*cp == '#')
+					press(tty, 193);
+				if (*cp == 'S')
+					press(tty, 197);
+				else if (*cp == 'E')
+					press(tty, 198);
+				else if (*cp == 'C')
+					press(tty, 199);
+				else if (*cp == '<')
+					press(tty, 200);
+				else if (*cp == '>')
+					press(tty, 201);
+				CHB->state = ST_EOL;
+				break;
+
+			/* AT*EAPP */
+			case ST_EAPP:
+				CHB->state = ST_NUMBER;
+				CHB->new_state = ST_EAPP1;
+				break;
+			case ST_EAPP1:
+				if (CHB->value == 0 && *cp == ',') {
+					NEXT_CHAR();
+					CHB->state = ST_NUMBER;
+					CHB->new_state = ST_EAPP2;
+				} else if (CHB->value == 1) {
+					press(tty, 196);
+					CHB->state = ST_EOL;
+				} else
+					CHB->state = ST_EOL;
+				break;
+			case ST_EAPP2:
+				if (CHB->value == 0) {
+					press(tty, 195);
+					CHB->state = ST_EOL;
+				} else if (CHB->value == 5 && *cp == ',') {
+					CHB->expect = ",\"";
+					CHB->new_state = ST_EAPP3;
+					CHB->state = ST_MATCH;
+
+				} else
+					CHB->state = ST_EOL;
+				break;
+			case ST_EAPP3:
+				if (*cp == 'W')
+					press(tty, 192);
+				else if (*cp == 'T')
+					press(tty, 194);
+				CHB->state = ST_EOL;
+				break;
+
+			case ST_DEBUGNR:
+				printk(KERN_INFO "chatboard: %d\n", CHB->value);
+				CHB->state = ST_EOL;
+				break;
+		}
+	}
+#undef NEXT_CHAR
+}
+
+/* how many characters we accept from the chatboard? */
+static int ld_recv_room(struct tty_struct * tty)
+{
+	return 65536;
+}
+
+struct tty_ldisc chatboard_ldisc = {
+	magic: TTY_LDISC_MAGIC,
+	name: "chatboard",
+	flags: 0,
+	open: ld_open, /* initialize the state machine */
+	close: ld_close,
+	receive_buf: ld_receive,
+	receive_room: ld_recv_room,
+	write_wakeup: ld_write,
+};
+
+static int __init chatboard_init(void)
+{
+	if (tty_register_ldisc(N_CHATBOARD, &chatboard_ldisc) != 0) {
+		printk(KERN_ERR "chatboard: cannot register ldisc\n");
+		return -1;
+	}
+	printk(KERN_INFO "chatboard: version %s, Milan Pikula <www@terminus.sk>\n", VERSION);
+	return 0;
+}
+
+void chatboard_exit(void)
+{
+	tty_register_ldisc(N_CHATBOARD, NULL);
+}
+
+
+module_init(chatboard_init);
+module_exit(chatboard_exit);
+
+#ifdef MODULE
+MODULE_AUTHOR("Milan Pikula <www@terminus.sk>");
+MODULE_DESCRIPTION("Ericsson Chatboard keyboard driver");
+#endif
