
From: Ralf Baechle <ralf@linux-mips.org>

Update Turbochannel code.  Right now the code is basically still at the state
of 2.3; with this patch applied it'll roughly on the level of the TC code in
early 2.4 with a bunch of 2.6 fixes on top.  Not great but will bring the code
closer into touch with reality until Maciej has a chance to finally tackle
things.

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

 25-akpm/drivers/tc/lk201.c |  443 ++++++++++++++++++++++---------
 25-akpm/drivers/tc/lk201.h |  144 +++++++---
 25-akpm/drivers/tc/tc.c    |  179 ++++++------
 25-akpm/drivers/tc/zs.c    |  639 +++++++++++++++++++++------------------------
 25-akpm/drivers/tc/zs.h    |   68 ++--
 5 files changed, 862 insertions(+), 611 deletions(-)

diff -puN drivers/tc/lk201.c~mips-decstation-turbochannel-updates drivers/tc/lk201.c
--- 25/drivers/tc/lk201.c~mips-decstation-turbochannel-updates	2005-01-29 11:26:05.128968200 -0800
+++ 25-akpm/drivers/tc/lk201.c	2005-01-29 11:26:05.151964704 -0800
@@ -4,20 +4,44 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
+ * Copyright (C) 1999-2002 Harald Koerfgen <hkoerfg@web.de>
+ * Copyright (C) 2001, 2002, 2003, 2004  Maciej W. Rozycki
  */
+
+#include <linux/config.h>
+
 #include <linux/errno.h>
+#include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kbd_ll.h>
-#include <asm/wbflush.h>
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+
+#include <asm/keyboard.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/machtype.h>
+#include <asm/dec/serial.h>
 
-#include "zs.h"
 #include "lk201.h"
 
+/*
+ * Only handle DECstations that have an LK201 interface.
+ * Maxine uses LK501 at the Access.Bus and various DECsystems
+ * have no keyboard interface at all.
+ */
+#define LK_IFACE	(mips_machtype == MACH_DS23100    || \
+			 mips_machtype == MACH_DS5000_200 || \
+			 mips_machtype == MACH_DS5000_1XX || \
+			 mips_machtype == MACH_DS5000_2X0)
+/*
+ * These use the Z8530 SCC.  Others use the DZ11.
+ */
+#define LK_IFACE_ZS	(mips_machtype == MACH_DS5000_1XX || \
+			 mips_machtype == MACH_DS5000_2X0)
+
 /* Simple translation table for the SysRq keys */
 
 #ifdef CONFIG_MAGIC_SYSRQ
@@ -27,25 +51,29 @@
  */
 unsigned char lk201_sysrq_xlate[128];
 unsigned char *kbd_sysrq_xlate = lk201_sysrq_xlate;
+
+unsigned char kbd_sysrq_key = -1;
 #endif
 
 #define KEYB_LINE	3
 
-static int __init lk201_init(struct dec_serial *);
-static void __init lk201_info(struct dec_serial *);
-static void lk201_kbd_rx_char(unsigned char, unsigned char);
-
-struct zs_hook lk201_kbdhook = {
-	.init_channel   = lk201_init,
-	.init_info      = lk201_info,
-	.cflags         = B4800 | CS8 | CSTOPB | CLOCAL
+static int __init lk201_init(void *);
+static void __init lk201_info(void *);
+static void lk201_rx_char(unsigned char, unsigned char);
+
+static struct dec_serial_hook lk201_hook = {
+	.init_channel	= lk201_init,
+	.init_info	= lk201_info,
+	.rx_char	= NULL,
+	.poll_rx_char	= NULL,
+	.poll_tx_char	= NULL,
+	.cflags		= B4800 | CS8 | CSTOPB | CLOCAL,
 };
 
 /*
  * This is used during keyboard initialisation
  */
 static unsigned char lk201_reset_string[] = {
-	LK_CMD_LEDS_ON, LK_PARAM_LED_MASK(0xf),	/* show we are resetting */
 	LK_CMD_SET_DEFAULTS,
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 1),
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 2),
@@ -61,28 +89,199 @@ static unsigned char lk201_reset_string[
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 12),
 	LK_CMD_MODE(LK_MODE_DOWN, 13),
 	LK_CMD_MODE(LK_MODE_RPT_DOWN, 14),
-	LK_CMD_ENB_RPT,
 	LK_CMD_DIS_KEYCLK,
-	LK_CMD_RESUME,
 	LK_CMD_ENB_BELL, LK_PARAM_VOLUME(4),
-	LK_CMD_LEDS_OFF, LK_PARAM_LED_MASK(0xf)
 };
 
-static int __init lk201_reset(struct dec_serial *info)
+static void *lk201_handle;
+
+static int lk201_send(unsigned char ch)
+{
+	if (lk201_hook.poll_tx_char(lk201_handle, ch)) {
+		printk(KERN_ERR "lk201: transmit timeout\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+static inline int lk201_get_id(void)
+{
+	return lk201_send(LK_CMD_REQ_ID);
+}
+
+static int lk201_reset(void)
+{
+	int i, r;
+
+	for (i = 0; i < sizeof(lk201_reset_string); i++) {
+		r = lk201_send(lk201_reset_string[i]);
+		if (r < 0)
+			return r;
+	}
+	return 0;
+}
+
+static void lk201_report(unsigned char id[6])
+{
+	char *report = "lk201: keyboard attached, ";
+
+	switch (id[2]) {
+	case LK_STAT_PWRUP_OK:
+		printk(KERN_INFO "%sself-test OK\n", report);
+		break;
+	case LK_STAT_PWRUP_KDOWN:
+		/* The keyboard will resend the power-up ID
+		   after all keys are released, so we don't
+		   bother handling the error specially.  Still
+		   there may be a short-circuit inside.
+		 */
+		printk(KERN_ERR "%skey down (stuck?), code: 0x%02x\n",
+		       report, id[3]);
+		break;
+	case LK_STAT_PWRUP_ERROR:
+		printk(KERN_ERR "%sself-test failure\n", report);
+		break;
+	default:
+		printk(KERN_ERR "%sunknown error: 0x%02x\n",
+		       report, id[2]);
+	}
+}
+
+static void lk201_id(unsigned char id[6])
+{
+	/*
+	 * Report whether there is an LK201 or an LK401
+	 * The LK401 has ALT keys...
+	 */
+	switch (id[4]) {
+	case 1:
+		printk(KERN_INFO "lk201: LK201 detected\n");
+		break;
+	case 2:
+		printk(KERN_INFO "lk201: LK401 detected\n");
+		break;
+	case 3:
+		printk(KERN_INFO "lk201: LK443 detected\n");
+		break;
+	case 4:
+		printk(KERN_INFO "lk201: LK421 detected\n");
+		break;
+	default:
+		printk(KERN_WARNING
+		       "lk201: unknown keyboard detected, ID %d\n", id[4]);
+		printk(KERN_WARNING "lk201: ... please report to "
+		       "<linux-mips@linux-mips.org>\n");
+	}
+}
+
+#define DEFAULT_KEYB_REP_DELAY	(250/5)	/* [5ms] */
+#define DEFAULT_KEYB_REP_RATE	30	/* [cps] */
+
+static struct kbd_repeat kbdrate = {
+	DEFAULT_KEYB_REP_DELAY,
+	DEFAULT_KEYB_REP_RATE
+};
+
+static void parse_kbd_rate(struct kbd_repeat *r)
 {
+	if (r->delay <= 0)
+		r->delay = kbdrate.delay;
+	if (r->rate <= 0)
+		r->rate = kbdrate.rate;
+
+	if (r->delay < 5)
+		r->delay = 5;
+	if (r->delay > 630)
+		r->delay = 630;
+	if (r->rate < 12)
+		r->rate = 12;
+	if (r->rate > 127)
+		r->rate = 127;
+	if (r->rate == 125)
+		r->rate = 124;
+}
+
+static int write_kbd_rate(struct kbd_repeat *rep)
+{
+	int delay, rate;
 	int i;
 
-	for (i = 0; i < sizeof(lk201_reset_string); i++)
-		if (info->hook->poll_tx_char(info, lk201_reset_string[i])) {
-			printk("%s transmit timeout\n", __FUNCTION__);
-			return -EIO;
-		}
+	delay = rep->delay / 5;
+	rate = rep->rate;
+	for (i = 0; i < 4; i++) {
+		if (lk201_hook.poll_tx_char(lk201_handle,
+					    LK_CMD_RPT_RATE(i)))
+			return 1;
+		if (lk201_hook.poll_tx_char(lk201_handle,
+					    LK_PARAM_DELAY(delay)))
+			return 1;
+		if (lk201_hook.poll_tx_char(lk201_handle,
+					    LK_PARAM_RATE(rate)))
+			return 1;
+	}
 	return 0;
 }
 
+static int lk201_kbd_rate(struct kbd_repeat *rep)
+{
+	if (rep == NULL)
+		return -EINVAL;
+
+	parse_kbd_rate(rep);
+
+	if (write_kbd_rate(rep)) {
+		memcpy(rep, &kbdrate, sizeof(struct kbd_repeat));
+		return -EIO;
+	}
+
+	memcpy(&kbdrate, rep, sizeof(struct kbd_repeat));
+
+	return 0;
+}
+
+static void lk201_kd_mksound(unsigned int hz, unsigned int ticks)
+{
+	if (!ticks)
+		return;
+
+	/*
+	 * Can't set frequency and we "approximate"
+	 * duration by volume. ;-)
+	 */
+	ticks /= HZ / 32;
+	if (ticks > 7)
+		ticks = 7;
+	ticks = 7 - ticks;
+
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_ENB_BELL))
+		return;
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_VOLUME(ticks)))
+		return;
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_BELL))
+		return;
+}
+
 void kbd_leds(unsigned char leds)
 {
-	return;
+	unsigned char l = 0;
+
+	if (!lk201_handle)		/* FIXME */
+		return;
+
+	/* FIXME -- Only Hold and Lock LEDs for now. --macro */
+	if (leds & LED_SCR)
+		l |= LK_LED_HOLD;
+	if (leds & LED_CAP)
+		l |= LK_LED_LOCK;
+
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_ON))
+		return;
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(l)))
+		return;
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_CMD_LEDS_OFF))
+		return;
+	if (lk201_hook.poll_tx_char(lk201_handle, LK_PARAM_LED_MASK(~l)))
+		return;
 }
 
 int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
@@ -107,128 +306,136 @@ char kbd_unexpected_up(unsigned char key
 	return 0x80;
 }
 
-static void lk201_kbd_rx_char(unsigned char ch, unsigned char stat)
+static void lk201_rx_char(unsigned char ch, unsigned char fl)
 {
+	static unsigned char id[6];
+	static int id_i;
+
 	static int shift_state = 0;
 	static int prev_scancode;
 	unsigned char c = scancodeRemap[ch];
 
-	if (!stat || stat == 4) {
-		switch (ch) {
-		case LK_KEY_ACK:
-			break;
-		case LK_KEY_LOCK:
-			shift_state ^= LK_LOCK;
-			handle_scancode(c, shift_state && LK_LOCK ? 1 : 0);
-			break;
-		case LK_KEY_SHIFT:
-			shift_state ^= LK_SHIFT;
-			handle_scancode(c, shift_state && LK_SHIFT ? 1 : 0);
-			break;
-		case LK_KEY_CTRL:
-			shift_state ^= LK_CTRL;
-			handle_scancode(c, shift_state && LK_CTRL ? 1 : 0);
-			break;
-		case LK_KEY_COMP:
-			shift_state ^= LK_COMP;
-			handle_scancode(c, shift_state && LK_COMP ? 1 : 0);
-			break;
-		case LK_KEY_RELEASE:
-			if (shift_state & LK_SHIFT)
-				handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
-			if (shift_state & LK_CTRL)
-				handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
-			if (shift_state & LK_COMP)
-				handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
-			if (shift_state & LK_LOCK)
-				handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
-			shift_state = 0;
-			break;
-		case LK_KEY_REPEAT:
-			handle_scancode(prev_scancode, 1);
-			break;
-		default:
-			prev_scancode = c;
-			handle_scancode(c, 1);
-			break;
+	if (fl != TTY_NORMAL && fl != TTY_OVERRUN) {
+		printk(KERN_ERR "lk201: keyboard receive error: 0x%02x\n", fl);
+		return;
+	}
+
+	/* Assume this is a power-up ID. */
+	if (ch == LK_STAT_PWRUP_ID && !id_i) {
+		id[id_i++] = ch;
+		return;
+	}
+
+	/* Handle the power-up sequence. */
+	if (id_i) {
+		id[id_i++] = ch;
+		if (id_i == 4) {
+			/* OK, the power-up concluded. */
+			lk201_report(id);
+			if (id[2] == LK_STAT_PWRUP_OK)
+				lk201_get_id();
+			else {
+				id_i = 0;
+				printk(KERN_ERR "lk201: keyboard power-up "
+				       "error, skipping initialization\n");
+			}
+		} else if (id_i == 6) {
+			/* We got the ID; report it and start operation. */
+			id_i = 0;
+			lk201_id(id);
+			lk201_reset();
 		}
-	} else
-		printk("Error reading LKx01 keyboard: 0x%02x\n", stat);
+		return;
+	}
+
+	/* Everything else is a scancode/status response. */
+	id_i = 0;
+	switch (ch) {
+	case LK_STAT_RESUME_ERR:
+	case LK_STAT_ERROR:
+	case LK_STAT_INHIBIT_ACK:
+	case LK_STAT_TEST_ACK:
+	case LK_STAT_MODE_KEYDOWN:
+	case LK_STAT_MODE_ACK:
+		break;
+	case LK_KEY_LOCK:
+		shift_state ^= LK_LOCK;
+		handle_scancode(c, (shift_state & LK_LOCK) ? 1 : 0);
+		break;
+	case LK_KEY_SHIFT:
+		shift_state ^= LK_SHIFT;
+		handle_scancode(c, (shift_state & LK_SHIFT) ? 1 : 0);
+		break;
+	case LK_KEY_CTRL:
+		shift_state ^= LK_CTRL;
+		handle_scancode(c, (shift_state & LK_CTRL) ? 1 : 0);
+		break;
+	case LK_KEY_COMP:
+		shift_state ^= LK_COMP;
+		handle_scancode(c, (shift_state & LK_COMP) ? 1 : 0);
+		break;
+	case LK_KEY_RELEASE:
+		if (shift_state & LK_SHIFT)
+			handle_scancode(scancodeRemap[LK_KEY_SHIFT], 0);
+		if (shift_state & LK_CTRL)
+			handle_scancode(scancodeRemap[LK_KEY_CTRL], 0);
+		if (shift_state & LK_COMP)
+			handle_scancode(scancodeRemap[LK_KEY_COMP], 0);
+		if (shift_state & LK_LOCK)
+			handle_scancode(scancodeRemap[LK_KEY_LOCK], 0);
+		shift_state = 0;
+		break;
+	case LK_KEY_REPEAT:
+		handle_scancode(prev_scancode, 1);
+		break;
+	default:
+		prev_scancode = c;
+		handle_scancode(c, 1);
+		break;
+	}
+	tasklet_schedule(&keyboard_tasklet);
 }
 
-static void __init lk201_info(struct dec_serial *info)
+static void __init lk201_info(void *handle)
 {
 }
 
-static int __init lk201_init(struct dec_serial *info)
+static int __init lk201_init(void *handle)
 {
-	unsigned int ch, id = 0;
-	int result;
-
-	printk("DECstation LK keyboard driver v0.04... ");
+	/* First install handlers. */
+	lk201_handle = handle;
+	kbd_rate = lk201_kbd_rate;
+	kd_mksound = lk201_kd_mksound;
 
-	result = lk201_reset(info);
-	if (result)
-		return result;
-	mdelay(10);
-
-	/*
-	 * Detect whether there is an LK201 or an LK401
-	 * The LK401 has ALT keys...
-	 */
-	info->hook->poll_tx_char(info, LK_CMD_REQ_ID);
-	while ((ch = info->hook->poll_rx_char(info)) > 0)
-		id = ch;
-
-	switch (id) {
-	case 1:
-		printk("LK201 detected\n");
-		break;
-	case 2:
-		printk("LK401 detected\n");
-		break;
-	default:
-		printk("unknown keyboard, ID %d,\n", id);
-		printk("... please report to <linux-mips@oss.sgi.com>\n");
-	}
+	lk201_hook.rx_char = lk201_rx_char;
 
-	/*
-	 * now we're ready
-	 */
-	info->hook->rx_char = lk201_kbd_rx_char;
+	/* Then just issue a reset -- the handlers will do the rest. */
+	lk201_send(LK_CMD_POWER_UP);
 
 	return 0;
 }
 
 void __init kbd_init_hw(void)
 {
-	extern int register_zs_hook(unsigned int, struct zs_hook *);
-	extern int unregister_zs_hook(unsigned int);
+	/* Maxine uses LK501 at the Access.Bus. */
+	if (!LK_IFACE)
+		return;
 
-	if (TURBOCHANNEL) {
-		if (mips_machtype != MACH_DS5000_XX) {
-			/*
-			 * This is not a MAXINE, so:
-			 *
-			 * kbd_init_hw() is being called before
-			 * rs_init() so just register the kbd hook
-			 * and let zs_init do the rest :-)
-			 */
-			if (mips_machtype == MACH_DS5000_200)
-				printk("LK201 Support for DS5000/200 not yet ready ...\n");
-			else
-				if(!register_zs_hook(KEYB_LINE, &lk201_kbdhook))
-					unregister_zs_hook(KEYB_LINE);
-		}
+	printk(KERN_INFO "lk201: DECstation LK keyboard driver v0.05.\n");
+
+	if (LK_IFACE_ZS) {
+		/*
+		 * kbd_init_hw() is being called before
+		 * rs_init() so just register the kbd hook
+		 * and let zs_init do the rest :-)
+		 */
+		if (!register_dec_serial_hook(KEYB_LINE, &lk201_hook))
+			unregister_dec_serial_hook(KEYB_LINE);
 	} else {
 		/*
 		 * TODO: modify dz.c to allow similar hooks
 		 * for LK201 handling on DS2100, DS3100, and DS5000/200
 		 */
-		printk("LK201 Support for DS3100 not yet ready ...\n");
+		printk(KERN_ERR "lk201: support for DZ11 not yet ready.\n");
 	}
 }
-
-
-
-
diff -puN drivers/tc/lk201.h~mips-decstation-turbochannel-updates drivers/tc/lk201.h
--- 25/drivers/tc/lk201.h~mips-decstation-turbochannel-updates	2005-01-29 11:26:05.130967896 -0800
+++ 25-akpm/drivers/tc/lk201.h	2005-01-29 11:26:05.146965464 -0800
@@ -2,52 +2,124 @@
  *	Commands to the keyboard processor
  */
 
-#define	LK_PARAM		0x80	/* start/end parameter list */
+#define LK_PARAM		0x80	/* start/end parameter list */
 
-#define	LK_CMD_RESUME		0x8b
-#define	LK_CMD_INHIBIT		0xb9
-#define	LK_CMD_LEDS_ON		0x13	/* 1 param: led bitmask */
-#define	LK_CMD_LEDS_OFF		0x11	/* 1 param: led bitmask */
-#define	LK_CMD_DIS_KEYCLK	0x99
-#define	LK_CMD_ENB_KEYCLK	0x1b	/* 1 param: volume */
-#define	LK_CMD_DIS_CTLCLK	0xb9
-#define	LK_CMD_ENB_CTLCLK	0xbb
-#define	LK_CMD_SOUND_CLK	0x9f
-#define	LK_CMD_DIS_BELL		0xa1
-#define	LK_CMD_ENB_BELL		0x23	/* 1 param: volume */
-#define	LK_CMD_BELL		0xa7
-#define	LK_CMD_TMP_NORPT	0xc1
-#define	LK_CMD_ENB_RPT		0xe3
-#define	LK_CMD_DIS_RPT		0xe1
-#define	LK_CMD_RPT_TO_DOWN	0xd9
-#define	LK_CMD_REQ_ID		0xab
-#define	LK_CMD_POWER_UP		0xfd
-#define	LK_CMD_TEST_MODE	0xcb
-#define	LK_CMD_SET_DEFAULTS	0xd3
+#define LK_CMD_RESUME		0x8b	/* resume transmission to the host */
+#define LK_CMD_INHIBIT		0x89	/* stop transmission to the host */
+#define LK_CMD_LEDS_ON		0x13	/* light LEDs */
+					/* 1st param: led bitmask */
+#define LK_CMD_LEDS_OFF		0x11	/* turn off LEDs */
+					/* 1st param: led bitmask */
+#define LK_CMD_DIS_KEYCLK	0x99	/* disable the keyclick */
+#define LK_CMD_ENB_KEYCLK	0x1b	/* enable the keyclick */
+					/* 1st param: volume */
+#define LK_CMD_DIS_CTLCLK	0xb9	/* disable the Ctrl keyclick */
+#define LK_CMD_ENB_CTLCLK	0xbb	/* enable the Ctrl keyclick */
+#define LK_CMD_SOUND_CLK	0x9f	/* emit a keyclick */
+#define LK_CMD_DIS_BELL		0xa1	/* disable the bell */
+#define LK_CMD_ENB_BELL		0x23	/* enable the bell */
+					/* 1st param: volume */
+#define LK_CMD_BELL		0xa7	/* emit a bell */
+#define LK_CMD_TMP_NORPT	0xd1	/* disable typematic */
+					/* for the currently pressed key */
+#define LK_CMD_ENB_RPT		0xe3	/* enable typematic */
+					/* for RPT_DOWN groups */
+#define LK_CMD_DIS_RPT		0xe1	/* disable typematic */
+					/* for RPT_DOWN groups */
+#define LK_CMD_RPT_TO_DOWN	0xd9	/* set RPT_DOWN groups to DOWN */
+#define LK_CMD_REQ_ID		0xab	/* request the keyboard ID */
+#define LK_CMD_POWER_UP		0xfd	/* init power-up sequence */
+#define LK_CMD_TEST_MODE	0xcb	/* enter the factory test mode */
+#define LK_CMD_TEST_EXIT	0x80	/* exit the factory test mode */
+#define LK_CMD_SET_DEFAULTS	0xd3	/* set power-up defaults */
+
+#define LK_CMD_MODE(m,div)	(LK_PARAM|(((div)&0xf)<<3)|(((m)&0x3)<<1))
+					/* select the repeat mode */
+					/* for the selected key group */
+#define LK_CMD_MODE_AR(m,div)	((((div)&0xf)<<3)|(((m)&0x3)<<1))
+					/* select the repeat mode */
+					/* and the repeat register */
+					/* for the selected key group */
+					/* 1st param: register number */
+#define LK_CMD_RPT_RATE(r)	(0x78|(((r)&0x3)<<1))
+					/* set the delay and repeat rate */
+					/* for the selected repeat register */
+					/* 1st param: initial delay */
+					/* 2nd param: repeat rate */
 
 /* there are 4 leds, represent them in the low 4 bits of a byte */
-#define	LK_PARAM_LED_MASK(ledbmap)	(LK_PARAM|(ledbmap))
+#define LK_PARAM_LED_MASK(ledbmap)	(LK_PARAM|((ledbmap)&0xf))
+#define LK_LED_WAIT		0x1	/* Wait LED */
+#define LK_LED_COMP		0x2	/* Compose LED */
+#define LK_LED_LOCK		0x4	/* Lock LED */
+#define LK_LED_HOLD		0x8	/* Hold Screen LED */
 
 /* max volume is 0, lowest is 0x7 */
-#define	LK_PARAM_VOLUME(v)		(LK_PARAM|((v)&0x7))
+#define LK_PARAM_VOLUME(v)		(LK_PARAM|((v)&0x7))
 
-/* mode set command(s) details */
-#define	LK_MODE_DOWN		0x0
-#define	LK_MODE_RPT_DOWN	0x2
-#define	LK_MODE_DOWN_UP		0x6
-#define	LK_CMD_MODE(m,div)	(LK_PARAM|(div<<3)|m)
+/* mode set command details, div is a key group number */
+#define LK_MODE_DOWN		0x0	/* make only */
+#define LK_MODE_RPT_DOWN	0x1	/* make and typematic */
+#define LK_MODE_DOWN_UP		0x3	/* make and release */
+
+/* there are 4 repeat registers */
+#define LK_PARAM_AR(r)		(LK_PARAM|((v)&0x3))
+
+/*
+ * Mappings between key groups and keycodes are as follows:
+ *
+ *  1: 0xbf - 0xff -- alphanumeric,
+ *  2: 0x91 - 0xa5 -- numeric keypad,
+ *  3: 0xbc        -- Backspace,
+ *  4: 0xbd - 0xbe -- Tab, Return,
+ *  5: 0xb0 - 0xb2 -- Lock, Compose Character,
+ *  6: 0xad - 0xaf -- Ctrl, Shift,
+ *  7: 0xa6 - 0xa8 -- Left Arrow, Right Arrow,
+ *  8: 0xa9 - 0xac -- Up Arrow, Down Arrow, Right Shift,
+ *  9: 0x88 - 0x90 -- editor keypad,
+ * 10: 0x56 - 0x62 -- F1 - F5,
+ * 11: 0x63 - 0x6e -- F6 - F10,
+ * 12: 0x6f - 0x7a -- F11 - F14,
+ * 13: 0x7b - 0x7d -- Help, Do,
+ * 14: 0x7e - 0x87 -- F17 - F20.
+ *
+ * Notes:
+ * 1. Codes in the 0x00 - 0x40 range are reserved.
+ * 2. The assignment of the 0x41 - 0x55 range is undiscovered, probably 10.
+ */
+
+/* delay is 5 - 630 ms; 0x00 and 0x7f are reserved */
+#define LK_PARAM_DELAY(t)	((t)&0x7f)
+
+/* rate is 12 - 127 Hz; 0x00 - 0x0b and 0x7d (power-up!) are reserved */
+#define LK_PARAM_RATE(r)	(LK_PARAM|((r)&0x7f))
 
 #define LK_SHIFT 1<<0
 #define LK_CTRL 1<<1
 #define LK_LOCK 1<<2
 #define LK_COMP 1<<3
 
-#define LK_KEY_SHIFT 174
-#define LK_KEY_CTRL 175
-#define LK_KEY_LOCK 176
-#define LK_KEY_COMP 177
-#define LK_KEY_RELEASE 179
-#define LK_KEY_REPEAT 180
-#define LK_KEY_ACK 186
+#define LK_KEY_SHIFT		0xae
+#define LK_KEY_CTRL		0xaf
+#define LK_KEY_LOCK		0xb0
+#define LK_KEY_COMP		0xb1
+
+#define LK_KEY_RELEASE		0xb3	/* all keys released */
+#define LK_KEY_REPEAT		0xb4	/* repeat the last key */
+
+/* status responses */
+#define LK_STAT_RESUME_ERR	0xb5	/* keystrokes lost while inhibited */
+#define LK_STAT_ERROR		0xb6	/* an invalid command received */
+#define LK_STAT_INHIBIT_ACK	0xb7	/* transmission inhibited */
+#define LK_STAT_TEST_ACK	0xb8	/* the factory test mode entered */
+#define LK_STAT_MODE_KEYDOWN	0xb9	/* a key is down on a change */
+					/* to the DOWN_UP mode; */
+					/* the keycode follows */
+#define LK_STAT_MODE_ACK	0xba	/* the mode command succeeded */
+
+#define LK_STAT_PWRUP_ID	0x01	/* the power-up response start mark */
+#define LK_STAT_PWRUP_OK	0x00	/* the power-up self test OK */
+#define LK_STAT_PWRUP_KDOWN	0x3d	/* a key was down during the test */
+#define LK_STAT_PWRUP_ERROR	0x3e	/* keyboard self test failure */
 
-extern unsigned char scancodeRemap[256];
\ No newline at end of file
+extern unsigned char scancodeRemap[256];
diff -puN drivers/tc/tc.c~mips-decstation-turbochannel-updates drivers/tc/tc.c
--- 25/drivers/tc/tc.c~mips-decstation-turbochannel-updates	2005-01-29 11:26:05.131967744 -0800
+++ 25-akpm/drivers/tc/tc.c	2005-01-29 11:26:05.149965008 -0800
@@ -8,46 +8,46 @@
  * for more details.
  *
  * Copyright (c) Harald Koerfgen, 1998
+ * Copyright (c) 2001, 2003  Maciej W. Rozycki
  */
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
 #include <asm/addrspace.h>
 #include <asm/errno.h>
 #include <asm/dec/machtype.h>
+#include <asm/dec/prom.h>
 #include <asm/dec/tcinfo.h>
 #include <asm/dec/tcmodule.h>
 #include <asm/dec/interrupts.h>
-
+#include <asm/paccess.h>
 #include <asm/ptrace.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
 
 #define TC_DEBUG
 
 MODULE_LICENSE("GPL");
 slot_info tc_bus[MAX_SLOT];
-static int max_tcslot;
+static int num_tcslots;
 static tcinfo *info;
 
 unsigned long system_base;
 
-extern void (*dbe_board_handler)(struct pt_regs *regs);
-extern unsigned long *(*rex_slot_address)(int);
-extern void *(*rex_gettcinfo)(void);
-
 /*
  * Interface to the world. Read comment in include/asm-mips/tc.h.
  */
 
-int search_tc_card(char *name)
+int search_tc_card(const char *name)
 {
 	int slot;
 	slot_info *sip;
 
-	for (slot = 0; slot <= max_tcslot; slot++) {
+	for (slot = 0; slot < num_tcslots; slot++) {
 		sip = &tc_bus[slot];
-		if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
+		if ((sip->flags & FREE) &&
+		    (strncmp(sip->name, name, strlen(name)) == 0)) {
 			return slot;
 		}
 	}
@@ -68,7 +68,8 @@ void claim_tc_card(int slot)
 void release_tc_card(int slot)
 {
 	if (tc_bus[slot].flags & FREE) {
-		printk("release_tc_card: attempting to release a card already free\n");
+		printk("release_tc_card: "
+		       "attempting to release a card already free\n");
 		return;
 	}
 	tc_bus[slot].flags &= ~IN_USE;
@@ -93,73 +94,84 @@ unsigned long get_tc_speed(void)
 /*
  * Probing for TURBOchannel modules
  */
-static void __init my_dbe_handler(struct pt_regs *regs)
+static void __init tc_probe(unsigned long startaddr, unsigned long size,
+			    int slots)
 {
-	regs->cp0_epc += 4;
-}
-
-static void __init tc_probe(unsigned long startaddr, unsigned long size, int max_slot)
-{
-	int i, slot;
+	int i, slot, err;
 	long offset;
+	unsigned char pattern[4];
 	unsigned char *module;
-	void (*old_be_handler)(struct pt_regs *regs);
-
-	/* Install our exception handler temporarily */
 
-	old_be_handler = dbe_board_handler;
-	dbe_board_handler = my_dbe_handler;
-	for (slot = 0; slot <= max_slot; slot++) {
+	for (slot = 0; slot < slots; slot++) {
 		module = (char *)(startaddr + slot * size);
-		offset = -1;
-		if (module[OLDCARD + TC_PATTERN0] == 0x55 && module[OLDCARD + TC_PATTERN1] == 0x00
-		  && module[OLDCARD + TC_PATTERN2] == 0xaa && module[OLDCARD + TC_PATTERN3] == 0xff)
-			offset = OLDCARD;
-		if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
-		  && module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
-			offset = 0;
-
-		if (offset != -1) {
-			tc_bus[slot].base_addr = (unsigned long)module;
-			for(i = 0; i < 8; i++) {
-				tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
-				tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i];
-				tc_bus[slot].name[i] = module[TC_MODULE + offset + 4 * i];
-			}
-			tc_bus[slot].firmware[8] = 0;
-			tc_bus[slot].vendor[8] = 0;
-			tc_bus[slot].name[8] = 0;
-			/*
-			 * Looks unneccesary, but we may change
-			 * TC? in the future
-			 */
-			switch (slot) {
-			case 0:
-				tc_bus[slot].interrupt = TC0;
-				break;
-			case 1:
-				tc_bus[slot].interrupt = TC1;
-				break;
-			case 2:
-				tc_bus[slot].interrupt = TC2;
-				break;
-			/*
-			 * Yuck! DS5000/200 onboard devices
-			 */
-			case 5:
-				tc_bus[slot].interrupt = SCSI_INT;
-				break;
-			case 6:
-				tc_bus[slot].interrupt = ETHER;
-				break;
-			default:
-				tc_bus[slot].interrupt = -1;
-				break;
-			}	
+
+		offset = OLDCARD;
+
+		err = 0;
+		err |= get_dbe(pattern[0], module + OLDCARD + TC_PATTERN0);
+		err |= get_dbe(pattern[1], module + OLDCARD + TC_PATTERN1);
+		err |= get_dbe(pattern[2], module + OLDCARD + TC_PATTERN2);
+		err |= get_dbe(pattern[3], module + OLDCARD + TC_PATTERN3);
+		if (err)
+			continue;
+
+		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+		    pattern[2] != 0xaa || pattern[3] != 0xff) {
+			offset = NEWCARD;
+
+			err = 0;
+			err |= get_dbe(pattern[0], module + TC_PATTERN0);
+			err |= get_dbe(pattern[1], module + TC_PATTERN1);
+			err |= get_dbe(pattern[2], module + TC_PATTERN2);
+			err |= get_dbe(pattern[3], module + TC_PATTERN3);
+			if (err)
+				continue;
 		}
-	}
 
-	dbe_board_handler = old_be_handler;
+		if (pattern[0] != 0x55 || pattern[1] != 0x00 ||
+		    pattern[2] != 0xaa || pattern[3] != 0xff)
+			continue;
+
+		tc_bus[slot].base_addr = (unsigned long)module;
+		for(i = 0; i < 8; i++) {
+			tc_bus[slot].firmware[i] =
+				module[TC_FIRM_VER + offset + 4 * i];
+			tc_bus[slot].vendor[i] =
+				module[TC_VENDOR + offset + 4 * i];
+			tc_bus[slot].name[i] =
+				module[TC_MODULE + offset + 4 * i];
+		}
+		tc_bus[slot].firmware[8] = 0;
+		tc_bus[slot].vendor[8] = 0;
+		tc_bus[slot].name[8] = 0;
+		/*
+		 * Looks unneccesary, but we may change
+		 * TC? in the future
+		 */
+		switch (slot) {
+		case 0:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC0];
+			break;
+		case 1:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC1];
+			break;
+		case 2:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC2];
+			break;
+		/*
+		 * Yuck! DS5000/200 onboard devices
+		 */
+		case 5:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC5];
+			break;
+		case 6:
+			tc_bus[slot].interrupt = dec_interrupt[DEC_IRQ_TC6];
+			break;
+		default:
+			tc_bus[slot].interrupt = -1;
+			break;
+		}
+	}
 }
 
 /*
@@ -189,15 +201,16 @@ void __init tc_init(void)
 
 	switch (mips_machtype) {
 	case MACH_DS5000_200:
-		max_tcslot = 6;
+		num_tcslots = 7;
 		break;
 	case MACH_DS5000_1XX:
 	case MACH_DS5000_2X0:
-		max_tcslot = 2;
+	case MACH_DS5900:
+		num_tcslots = 3;
 		break;
 	case MACH_DS5000_XX:
 	default:
-		max_tcslot = 1;
+		num_tcslots = 2;
 		break;
 	}
 
@@ -210,22 +223,22 @@ void __init tc_init(void)
 
 		slot_size = info->slot_size << 20;
 
-		tc_probe(slot0addr, slot_size, max_tcslot);
+		tc_probe(slot0addr, slot_size, num_tcslots);
 
   		/*
   		 * All TURBOchannel DECstations have the onboard devices
- 		 * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+ 		 * where the (num_tcslots + 0 or 1 on DS5k/xx) Option Module
  		 * would be.
  		 */
  		if(mips_machtype == MACH_DS5000_XX)
- 			i = 2;
-		else
  			i = 1;
- 		
- 	        system_base = slot0addr + slot_size * (max_tcslot + i);
+		else
+ 			i = 0;
+
+ 	        system_base = slot0addr + slot_size * (num_tcslots + i);
 
 #ifdef TC_DEBUG
-		for (i = 0; i <= max_tcslot; i++)
+		for (i = 0; i < num_tcslots; i++)
 			if (tc_bus[i].base_addr) {
 				printk("    slot %d: ", i);
 				printk("%s %s %s\n", tc_bus[i].vendor,
@@ -244,4 +257,4 @@ EXPORT_SYMBOL(release_tc_card);
 EXPORT_SYMBOL(get_tc_base_addr);
 EXPORT_SYMBOL(get_tc_irq_nr);
 EXPORT_SYMBOL(get_tc_speed);
-
+EXPORT_SYMBOL(system_base);
diff -puN drivers/tc/zs.c~mips-decstation-turbochannel-updates drivers/tc/zs.c
--- 25/drivers/tc/zs.c~mips-decstation-turbochannel-updates	2005-01-29 11:26:05.133967440 -0800
+++ 25-akpm/drivers/tc/zs.c	2005-01-29 11:26:05.145965616 -0800
@@ -6,7 +6,7 @@
  *
  * DECstation changes
  * Copyright (C) 1998-2000 Harald Koerfgen
- * Copyright (C) 2000,2001 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004  Maciej W. Rozycki
  *
  * For the rest of the code the original Copyright applies:
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
@@ -55,8 +55,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
-#include <linux/bitops.h>
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 #include <linux/console.h>
 #endif
 
@@ -65,18 +64,15 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
-#include <asm/wbflush.h>
 #include <asm/bootinfo.h>
+#include <asm/dec/serial.h>
+
 #ifdef CONFIG_MACH_DECSTATION
 #include <asm/dec/interrupts.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/tc.h>
 #include <asm/dec/ioasic_addrs.h>
 #endif
-#ifdef CONFIG_BAGET_MIPS
-#include <asm/baget/baget.h>
-unsigned long system_base;
-#endif
 #ifdef CONFIG_KGDB
 #include <asm/kgdb.h>
 #endif
@@ -94,7 +90,7 @@ unsigned long system_base;
 #define NUM_SERIAL	2		/* Max number of ZS chips supported */
 #define NUM_CHANNELS	(NUM_SERIAL * 2)	/* 2 channels per chip */
 #define CHANNEL_A_NR  (zs_parms->channel_a_offset > zs_parms->channel_b_offset)
-                                        /* Number of channel A in the chip */ 
+                                        /* Number of channel A in the chip */
 #define ZS_CHAN_IO_SIZE 8
 #define ZS_CLOCK        7372800 	/* Z8530 RTxC input clock rate */
 
@@ -105,7 +101,8 @@ struct zs_parms {
 	unsigned long scc1;
 	int channel_a_offset;
 	int channel_b_offset;
-	int irq;
+	int irq0;
+	int irq1;
 	int clock;
 };
 
@@ -113,24 +110,15 @@ static struct zs_parms *zs_parms;
 
 #ifdef CONFIG_MACH_DECSTATION
 static struct zs_parms ds_parms = {
-	scc0 : SCC0,
-	scc1 : SCC1,
+	scc0 : IOASIC_SCC0,
+	scc1 : IOASIC_SCC1,
 	channel_a_offset : 1,
 	channel_b_offset : 9,
-	irq : SERIAL,
+	irq0 : -1,
+	irq1 : -1,
 	clock : ZS_CLOCK
 };
 #endif
-#ifdef CONFIG_BAGET_MIPS
-static struct zs_parms baget_parms = {
-	scc0 : UNI_SCC0,
-	scc1 : UNI_SCC1,
-	channel_a_offset : 9,
-	channel_b_offset : 1,
-	irq : BAGET_SCC_IRQ,
-	clock : 14745000
-};
-#endif
 
 #ifdef CONFIG_MACH_DECSTATION
 #define DS_BUS_PRESENT (IOASIC)
@@ -138,13 +126,7 @@ static struct zs_parms baget_parms = {
 #define DS_BUS_PRESENT 0
 #endif
 
-#ifdef CONFIG_BAGET_MIPS
-#define BAGET_BUS_PRESENT (mips_machtype == MACH_BAGET202)
-#else
-#define BAGET_BUS_PRESENT 0
-#endif
-
-#define BUS_PRESENT (DS_BUS_PRESENT || BAGET_BUS_PRESENT)
+#define BUS_PRESENT (DS_BUS_PRESENT)
 
 struct dec_zschannel zs_channels[NUM_CHANNELS];
 struct dec_serial zs_soft[NUM_CHANNELS];
@@ -153,28 +135,28 @@ struct dec_serial *zs_chain;	/* list of 
 
 struct tty_struct zs_ttys[NUM_CHANNELS];
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 static struct console sercons;
 #endif
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) \
-    && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
 static unsigned long break_pressed; /* break, really ... */
 #endif
 
 static unsigned char zs_init_regs[16] __initdata = {
-	0,                           /* write 0 */
-	0,			     /* write 1 */
-	0xf0,                        /* write 2 */
-	(Rx8),                       /* write 3 */
-	(X16CLK | SB1),              /* write 4 */
-	(Tx8),                       /* write 5 */
-	0, 0, 0,                     /* write 6, 7, 8 */
-	(VIS),                       /* write 9 */
-	(NRZ),                       /* write 10 */
-	(TCBR | RCBR),               /* write 11 */
-	0, 0,                        /* BRG time constant, write 12 + 13 */
-	(BRSRC | BRENABL),           /* write 14 */
-	0 			     /* write 15 */
+	0,				/* write 0 */
+	0,				/* write 1 */
+	0,				/* write 2 */
+	0,				/* write 3 */
+	(X16CLK),			/* write 4 */
+	0,				/* write 5 */
+	0, 0, 0,			/* write 6, 7, 8 */
+	(MIE | DLC | NV),		/* write 9 */
+	(NRZ),				/* write 10 */
+	(TCBR | RCBR),			/* write 11 */
+	0, 0,				/* BRG time constant, write 12 + 13 */
+	(BRSRC | BRENABL),		/* write 14 */
+	0				/* write 15 */
 };
 
 DECLARE_TASK_QUEUE(tq_zs_serial);
@@ -190,7 +172,6 @@ static struct tty_driver *serial_driver;
 /*
  * Debugging.
  */
-#undef SERIAL_DEBUG_INTR
 #undef SERIAL_DEBUG_OPEN
 #undef SERIAL_DEBUG_FLOW
 #undef SERIAL_DEBUG_THROTTLE
@@ -251,7 +232,7 @@ static int baud_table[] = {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
 	9600, 19200, 38400, 57600, 115200, 0 };
 
-/* 
+/*
  * Reading and writing Z8530 registers.
  */
 static inline unsigned char read_zsreg(struct dec_zschannel *channel,
@@ -261,7 +242,7 @@ static inline unsigned char read_zsreg(s
 
 	if (reg != 0) {
 		*channel->control = reg & 0xf;
-		wbflush(); RECOVERY_DELAY;
+		fast_iob(); RECOVERY_DELAY;
 	}
 	retval = *channel->control;
 	RECOVERY_DELAY;
@@ -273,10 +254,10 @@ static inline void write_zsreg(struct de
 {
 	if (reg != 0) {
 		*channel->control = reg & 0xf;
-		wbflush(); RECOVERY_DELAY;
+		fast_iob(); RECOVERY_DELAY;
 	}
 	*channel->control = value;
-	wbflush(); RECOVERY_DELAY;
+	fast_iob(); RECOVERY_DELAY;
 	return;
 }
 
@@ -293,7 +274,7 @@ static inline void write_zsdata(struct d
 				unsigned char value)
 {
 	*channel->data = value;
-	wbflush(); RECOVERY_DELAY;
+	fast_iob(); RECOVERY_DELAY;
 	return;
 }
 
@@ -303,9 +284,9 @@ static inline void load_zsregs(struct de
 /*	ZS_CLEARERR(channel);
 	ZS_CLEARFIFO(channel); */
 	/* Load 'em up */
-	write_zsreg(channel, R4, regs[R4]);
 	write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
 	write_zsreg(channel, R5, regs[R5] & ~TxENAB);
+	write_zsreg(channel, R4, regs[R4]);
 	write_zsreg(channel, R9, regs[R9]);
 	write_zsreg(channel, R1, regs[R1]);
 	write_zsreg(channel, R2, regs[R2]);
@@ -372,8 +353,6 @@ static inline void rs_recv_clear(struct 
  * -----------------------------------------------------------------------
  */
 
-static int tty_break;	/* Set whenever BREAK condition is detected.  */
-
 /*
  * This routine is used by the interrupt handler to schedule
  * processing in the software interrupt portion of the driver.
@@ -397,23 +376,18 @@ static _INLINE_ void receive_chars(struc
 		stat = read_zsreg(info->zs_channel, R1);
 		ch = read_zsdata(info->zs_channel);
 
-		if (!tty && !info->hook && !info->hook->rx_char)
+		if (!tty && (!info->hook || !info->hook->rx_char))
 			continue;
 
-		if (tty_break) {
-			tty_break = 0;
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
-			if (info->line == sercons.index) {
-				if (!break_pressed) {
-					break_pressed = jiffies;
-					goto ignore_char;
-				}
-				break_pressed = 0;
-			}
-#endif
+		flag = TTY_NORMAL;
+		if (info->tty_break) {
+			info->tty_break = 0;
 			flag = TTY_BREAK;
 			if (info->flags & ZILOG_SAK)
 				do_SAK(tty);
+			/* Ignore the null char got when BREAK is removed.  */
+			if (ch == 0)
+				continue;
 		} else {
 			if (stat & Rx_OVR) {
 				flag = TTY_OVERRUN;
@@ -421,20 +395,22 @@ static _INLINE_ void receive_chars(struc
 				flag = TTY_FRAME;
 			} else if (stat & PAR_ERR) {
 				flag = TTY_PARITY;
-			} else
-				flag = 0;
-			if (flag)
+			}
+			if (flag != TTY_NORMAL)
 				/* reset the error indication */
 				write_zsreg(info->zs_channel, R0, ERR_RES);
 		}
 
-#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
 		if (break_pressed && info->line == sercons.index) {
-			if (ch != 0 &&
-			    time_before(jiffies, break_pressed + HZ*5)) {
+			/* Ignore the null char got when BREAK is removed.  */
+			if (ch == 0)
+				continue;
+			if (time_before(jiffies, break_pressed + HZ * 5)) {
 				handle_sysrq(ch, regs, NULL);
 				break_pressed = 0;
-				goto ignore_char;
+				continue;
 			}
 			break_pressed = 0;
 		}
@@ -444,22 +420,8 @@ static _INLINE_ void receive_chars(struc
 			(*info->hook->rx_char)(ch, flag);
 			return;
   		}
-		
-		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
-			static int flip_buf_ovf;
-			++flip_buf_ovf;
-			continue;
-		}
-		tty->flip.count++;
-		{
-			static int flip_max_cnt;
-			if (flip_max_cnt < tty->flip.count)
-				flip_max_cnt = tty->flip.count;
-		}
 
-		*tty->flip.flag_buf_ptr++ = flag;
-		*tty->flip.char_buf_ptr++ = ch;
-	ignore_char:
+		tty_insert_flip_char(tty, ch, flag);
 	}
 	if (tty)
 		tty_flip_buffer_push(tty);
@@ -501,18 +463,22 @@ static _INLINE_ void status_handle(struc
 	/* Get status from Read Register 0 */
 	stat = read_zsreg(info->zs_channel, R0);
 
-	if (stat & BRK_ABRT) {
-#ifdef SERIAL_DEBUG_INTR
-		printk("handling break....");
+	if ((stat & BRK_ABRT) && !(info->read_reg_zero & BRK_ABRT)) {
+#if defined(CONFIG_SERIAL_DEC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && \
+   !defined(MODULE)
+		if (info->line == sercons.index) {
+			if (!break_pressed)
+				break_pressed = jiffies;
+		} else
 #endif
-		tty_break = 1;
+			info->tty_break = 1;
 	}
 
 	if (info->zs_channel != info->zs_chan_a) {
 
-		/* FIXEM: Check for DCD transitions */
-		if (((stat ^ info->read_reg_zero) & DCD) != 0
-		    && info->tty && !C_CLOCAL(info->tty)) {
+		/* Check for DCD transitions */
+		if (info->tty && !C_CLOCAL(info->tty) &&
+		    ((stat ^ info->read_reg_zero) & DCD) != 0 ) {
 			if (stat & DCD) {
 				wake_up_interruptible(&info->open_wait);
 			} else {
@@ -563,7 +529,7 @@ void rs_interrupt(int irq, void *dev_id,
 		shift = 0;	/* Channel B */
 
 	for (;;) {
-		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift; 
+		zs_intreg = read_zsreg(info->zs_chan_a, R3) >> shift;
 		if ((zs_intreg & CHAN_IRQMASK) == 0)
 			break;
 
@@ -577,7 +543,7 @@ void rs_interrupt(int irq, void *dev_id,
 			status_handle(info);
 		}
 	}
-	
+
 	/* Why do we need this ? */
 	write_zsreg(info->zs_channel, 0, RES_H_IUS);
 }
@@ -586,14 +552,14 @@ void rs_interrupt(int irq, void *dev_id,
 void zs_dump (void) {
 	int i, j;
 	for (i = 0; i < zs_channels_found; i++) {
-		struct dec_zschannel *ch = &zs_channels[i]; 
+		struct dec_zschannel *ch = &zs_channels[i];
 		if ((long)ch->control == UNI_IO_BASE+UNI_SCC1A_CTRL) {
 			for (j = 0; j < 15; j++) {
-				printk("W%d = 0x%x\t", 
+				printk("W%d = 0x%x\t",
 				       j, (int)ch->curregs[j]);
 			}
 			for (j = 0; j < 15; j++) {
-				printk("R%d = 0x%x\t", 
+				printk("R%d = 0x%x\t",
 				       j, (int)read_zsreg(ch,j));
 			}
 			printk("\n\n");
@@ -622,7 +588,7 @@ static void rs_stop(struct tty_struct *t
 
 	if (serial_paranoia_check(info, tty->name, "rs_stop"))
 		return;
-	
+
 #if 1
 	save_flags(flags); cli();
 	if (info->zs_channel->curregs[5] & TxENAB) {
@@ -637,10 +603,10 @@ static void rs_start(struct tty_struct *
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
 	unsigned long flags;
-	
+
 	if (serial_paranoia_check(info, tty->name, "rs_start"))
 		return;
-	
+
 	save_flags(flags); cli();
 #if 1
 	if (info->xmit_cnt && info->xmit_buf && !(info->zs_channel->curregs[5] & TxENAB)) {
@@ -673,7 +639,7 @@ static void do_softint(void *private_)
 {
 	struct dec_serial	*info = (struct dec_serial *) private_;
 	struct tty_struct	*tty;
-	
+
 	tty = info->tty;
 	if (!tty)
 		return;
@@ -711,8 +677,13 @@ int zs_startup(struct dec_serial * info)
 	/*
 	 * Clear the interrupt registers.
 	 */
-	write_zsreg(info->zs_channel, 0, ERR_RES);
-	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+	write_zsreg(info->zs_channel, R0, ERR_RES);
+	write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+	/*
+	 * Set the speed of the serial port
+	 */
+	change_speed(info);
 
 	/*
 	 * Turn on RTS and DTR.
@@ -722,35 +693,30 @@ int zs_startup(struct dec_serial * info)
 	/*
 	 * Finally, enable sequencing and interrupts
 	 */
-	info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
-	info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
-	info->zs_channel->curregs[5] |= (TxENAB | Tx8);
-	info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
-	info->zs_channel->curregs[9] |= (VIS | MIE);
-	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);
-	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);
-	write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+	info->zs_channel->curregs[R1] &= ~RxINT_MASK;
+	info->zs_channel->curregs[R1] |= (RxINT_ALL | TxINT_ENAB |
+					  EXT_INT_ENAB);
+	info->zs_channel->curregs[R3] |= RxENABLE;
+	info->zs_channel->curregs[R5] |= TxENAB;
+	info->zs_channel->curregs[R15] |= (DCDIE | CTSIE | TxUIE | BRKIE);
+	write_zsreg(info->zs_channel, R1, info->zs_channel->curregs[R1]);
+	write_zsreg(info->zs_channel, R3, info->zs_channel->curregs[R3]);
+	write_zsreg(info->zs_channel, R5, info->zs_channel->curregs[R5]);
+	write_zsreg(info->zs_channel, R15, info->zs_channel->curregs[R15]);
 
 	/*
 	 * And clear the interrupt registers again for luck.
 	 */
-	write_zsreg(info->zs_channel, 0, ERR_RES);
-	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+	write_zsreg(info->zs_channel, R0, ERR_RES);
+	write_zsreg(info->zs_channel, R0, RES_H_IUS);
+
+	/* Save the current value of RR0 */
+	info->read_reg_zero = read_zsreg(info->zs_channel, R0);
 
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
 	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
 
-	/*
-	 * Set the speed of the serial port
-	 */
-	change_speed(info);
-
-	/* Save the current value of RR0 */
-	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
 	info->flags |= ZILOG_INITIALIZED;
 	restore_flags(flags);
 	return 0;
@@ -771,9 +737,9 @@ static void shutdown(struct dec_serial *
 	printk("Shutting down serial port %d (irq %d)....", info->line,
 	       info->irq);
 #endif
-	
+
 	save_flags(flags); cli(); /* Disable interrupts */
-	
+
 	if (info->xmit_buf) {
 		free_page((unsigned long) info->xmit_buf);
 		info->xmit_buf = 0;
@@ -833,13 +799,11 @@ static void change_speed(struct dec_seri
 
 	save_flags(flags); cli();
 	info->zs_baud = baud_table[i];
-	info->clk_divisor = 16;
 	if (info->zs_baud) {
-		info->zs_channel->curregs[4] = X16CLK;
 		brg = BPS_TO_BRG(info->zs_baud, zs_parms->clock/info->clk_divisor);
 		info->zs_channel->curregs[12] = (brg & 255);
 		info->zs_channel->curregs[13] = ((brg >> 8) & 255);
-		zs_rtsdtr(info, DTR, 1); 
+		zs_rtsdtr(info, DTR, 1);
 	} else {
 		zs_rtsdtr(info, RTS | DTR, 0);
 		return;
@@ -942,13 +906,21 @@ static int rs_write(struct tty_struct * 
 
 	save_flags(flags);
 	while (1) {
-		cli();		
-		c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-					  SERIAL_XMIT_SIZE - info->xmit_head));
+		cli();
+		c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
 		if (c <= 0)
 			break;
 
-		memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		if (from_user) {
+			down(&tmp_buf_sem);
+			copy_from_user(tmp_buf, buf, c);
+			c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			up(&tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
 		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
 		info->xmit_cnt += c;
 		restore_flags(flags);
@@ -968,7 +940,7 @@ static int rs_write_room(struct tty_stru
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
 	int	ret;
-				
+
 	if (serial_paranoia_check(info, tty->name, "rs_write_room"))
 		return 0;
 	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
@@ -980,7 +952,7 @@ static int rs_write_room(struct tty_stru
 static int rs_chars_in_buffer(struct tty_struct *tty)
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-			
+
 	if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
 		return 0;
 	return info->xmit_cnt;
@@ -989,7 +961,7 @@ static int rs_chars_in_buffer(struct tty
 static void rs_flush_buffer(struct tty_struct *tty)
 {
 	struct dec_serial *info = (struct dec_serial *)tty->driver_data;
-				
+
 	if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
 		return;
 	cli();
@@ -1001,7 +973,7 @@ static void rs_flush_buffer(struct tty_s
 /*
  * ------------------------------------------------------------
  * rs_throttle()
- * 
+ *
  * This routine is called by the upper-layer tty layer to signal that
  * incoming characters should be throttled.
  * ------------------------------------------------------------
@@ -1013,14 +985,14 @@ static void rs_throttle(struct tty_struc
 
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("throttle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "rs_throttle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		info->x_char = STOP_CHAR(tty);
@@ -1041,14 +1013,14 @@ static void rs_unthrottle(struct tty_str
 
 #ifdef SERIAL_DEBUG_THROTTLE
 	char	buf[64];
-	
+
 	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
 	       tty->ldisc.chars_in_buffer(tty));
 #endif
 
 	if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
 		return;
-	
+
 	if (I_IXOFF(tty)) {
 		save_flags(flags); cli();
 		if (info->x_char)
@@ -1145,7 +1117,7 @@ check_and_exit:
  * 	    release the bus after transmitting. This must be done when
  * 	    the transmit shift register is empty, not be done when the
  * 	    transmit holding register is empty.  This functionality
- * 	    allows an RS485 driver to be written in user space. 
+ * 	    allows an RS485 driver to be written in user space.
  */
 static int get_lsr_info(struct dec_serial * info, unsigned int *value)
 {
@@ -1192,7 +1164,7 @@ static int rs_tiocmget(struct tty_struct
 }
 
 static int rs_tiocmset(struct tty_struct *tty, struct file *file,
-		       unsigned int set, unsigned int clear)
+                       unsigned int set, unsigned int clear)
 {
 	struct dec_serial * info = (struct dec_serial *)tty->driver_data;
 	int error;
@@ -1210,6 +1182,7 @@ static int rs_tiocmset(struct tty_struct
 	if (info->zs_channel == info->zs_chan_a)
 		return 0;
 
+	get_user(arg, value);
 	cli();
 	if (set & TIOCM_RTS)
 		info->zs_chan_a->curregs[5] |= RTS;
@@ -1264,38 +1237,38 @@ static int rs_ioctl(struct tty_struct *t
 		if (tty->flags & (1 << TTY_IO_ERROR))
 		    return -EIO;
 	}
-	
+
 	switch (cmd) {
-		case TIOCGSERIAL:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct serial_struct));
-			if (error)
-				return error;
-			return get_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSSERIAL:
-			return set_serial_info(info,
-					       (struct serial_struct *) arg);
-		case TIOCSERGETLSR: /* Get line status register */
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-				sizeof(unsigned int));
-			if (error)
-				return error;
-			else
-			    return get_lsr_info(info, (unsigned int *) arg);
+	case TIOCGSERIAL:
+		error = verify_area(VERIFY_WRITE, (void *)arg,
+				    sizeof(struct serial_struct));
+		if (error)
+			return error;
+		return get_serial_info(info, (struct serial_struct *)arg);
+
+	case TIOCSSERIAL:
+		return set_serial_info(info, (struct serial_struct *)arg);
+
+	case TIOCSERGETLSR:			/* Get line status register */
+		error = verify_area(VERIFY_WRITE, (void *)arg,
+				    sizeof(unsigned int));
+		if (error)
+			return error;
+		else
+			return get_lsr_info(info, (unsigned int *)arg);
+
+	case TIOCSERGSTRUCT:
+		error = verify_area(VERIFY_WRITE, (void *)arg,
+				    sizeof(struct dec_serial));
+		if (error)
+			return error;
+		copy_from_user((struct dec_serial *)arg, info,
+			       sizeof(struct dec_serial));
+		return 0;
 
-		case TIOCSERGSTRUCT:
-			error = verify_area(VERIFY_WRITE, (void *) arg,
-						sizeof(struct dec_serial));
-			if (error)
-				return error;
-			copy_from_user((struct dec_serial *) arg,
-				       info, sizeof(struct dec_serial));
-			return 0;
-			
-		default:
-			return -ENOIOCTLCMD;
-		}
+	default:
+		return -ENOIOCTLCMD;
+	}
 	return 0;
 }
 
@@ -1317,7 +1290,7 @@ static void rs_set_termios(struct tty_st
 /*
  * ------------------------------------------------------------
  * rs_close()
- * 
+ *
  * This routine is called when the serial port gets closed.
  * Wait for the last remaining data to be sent.
  * ------------------------------------------------------------
@@ -1329,14 +1302,14 @@ static void rs_close(struct tty_struct *
 
 	if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
 		return;
-	
+
 	save_flags(flags); cli();
-	
+
 	if (tty_hung_up_p(filp)) {
 		restore_flags(flags);
 		return;
 	}
-	
+
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_close ttyS%d, count = %d\n", info->line, info->count);
 #endif
@@ -1363,7 +1336,7 @@ static void rs_close(struct tty_struct *
 	}
 	info->flags |= ZILOG_CLOSING;
 	/*
-	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * Now we wait for the transmit buffer to clear; and we notify
 	 * the line discipline to only process XON/XOFF characters.
 	 */
 	tty->closing = 1;
@@ -1411,7 +1384,8 @@ static void rs_close(struct tty_struct *
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
 {
 	struct dec_serial *info = (struct dec_serial *) tty->driver_data;
-	unsigned long orig_jiffies, char_time;
+	unsigned long orig_jiffies;
+	int char_time;
 
 	if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
 		return;
@@ -1427,7 +1401,7 @@ static void rs_wait_until_sent(struct tt
 	if (char_time == 0)
 		char_time = 1;
 	if (timeout)
-		char_time = min_t(unsigned long, char_time, timeout);
+		char_time = min(char_time, timeout);
 	while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(char_time);
@@ -1485,11 +1459,6 @@ static int block_til_ready(struct tty_st
 	}
 
 	/*
-	 * If this is a callout device, then just make sure the normal
-	 * device isn't being used.
-	 */
-	
-	/*
 	 * If non-blocking mode is set, or the port is not enabled,
 	 * then make the check up front and then exit.
 	 */
@@ -1516,7 +1485,7 @@ static int block_til_ready(struct tty_st
 	       info->line, info->count);
 #endif
 	cli();
-	if (!tty_hung_up_p(filp)) 
+	if (!tty_hung_up_p(filp))
 		info->count--;
 	sti();
 	info->blocked_open++;
@@ -1532,7 +1501,7 @@ static int block_til_ready(struct tty_st
 			if (info->flags & ZILOG_HUP_NOTIFY)
 				retval = -EAGAIN;
 			else
-				retval = -ERESTARTSYS;	
+				retval = -ERESTARTSYS;
 #else
 			retval = -EAGAIN;
 #endif
@@ -1564,7 +1533,7 @@ static int block_til_ready(struct tty_st
 		return retval;
 	info->flags |= ZILOG_NORMAL_ACTIVE;
 	return 0;
-}	
+}
 
 /*
  * This routine is called whenever a serial port is opened.  It
@@ -1626,7 +1595,7 @@ int rs_open(struct tty_struct *tty, stru
 		return retval;
 	}
 
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 	if (sercons.cflag && sercons.index == line) {
 		tty->termios->c_cflag = sercons.cflag;
 		sercons.cflag = 0;
@@ -1645,7 +1614,7 @@ int rs_open(struct tty_struct *tty, stru
 
 static void __init show_serial_version(void)
 {
-	printk("DECstation Z8530 serial driver version 0.05\n");
+	printk("DECstation Z8530 serial driver version 0.09\n");
 }
 
 /*  Initialize Z8530s zs_channels
@@ -1655,6 +1624,7 @@ static void __init probe_sccs(void)
 {
 	struct dec_serial **pp;
 	int i, n, n_chips = 0, n_channels, chip, channel;
+	unsigned long flags;
 
 	/*
 	 * did we get here by accident?
@@ -1663,7 +1633,7 @@ static void __init probe_sccs(void)
 		printk("Not on JUNKIO machine, skipping probe_sccs\n");
 		return;
 	}
-	
+
 	/*
 	 * When serial console is activated, tc_init has not been called yet
 	 * and system_base is undefined. Unfortunately we have to hardcode
@@ -1672,27 +1642,25 @@ static void __init probe_sccs(void)
 	switch(mips_machtype) {
 #ifdef CONFIG_MACH_DECSTATION
 	case MACH_DS5000_2X0:
-		system_base = 0xbf800000;
+	case MACH_DS5900:
+		system_base = KSEG1ADDR(0x1f800000);
 		n_chips = 2;
 		zs_parms = &ds_parms;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
 		break;
 	case MACH_DS5000_1XX:
-		system_base = 0xbc000000;
+		system_base = KSEG1ADDR(0x1c000000);
 		n_chips = 2;
 		zs_parms = &ds_parms;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
+		zs_parms->irq1 = dec_interrupt[DEC_IRQ_SCC1];
 		break;
 	case MACH_DS5000_XX:
-		system_base = 0xbc000000;
+		system_base = KSEG1ADDR(0x1c000000);
 		n_chips = 1;
 		zs_parms = &ds_parms;
-		break;
-#endif
-#ifdef CONFIG_BAGET_MIPS
-	case MACH_BAGET202:
-		system_base = UNI_IO_BASE;
-		n_chips = 2;
-		zs_parms = &baget_parms;
-		zs_init_regs[2] = 0x8;
+		zs_parms->irq0 = dec_interrupt[DEC_IRQ_SCC0];
 		break;
 #endif
 	default:
@@ -1710,15 +1678,15 @@ static void __init probe_sccs(void)
 			/*
 			 * The sccs reside on the high byte of the 16 bit IOBUS
 			 */
-			zs_channels[n_channels].control = 
-				(volatile unsigned char *)system_base + 
-			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + 
-			  (0 == channel ? zs_parms->channel_a_offset : 
+			zs_channels[n_channels].control =
+				(volatile unsigned char *)system_base +
+			  (0 == chip ? zs_parms->scc0 : zs_parms->scc1) +
+			  (0 == channel ? zs_parms->channel_a_offset :
 			                  zs_parms->channel_b_offset);
-			zs_channels[n_channels].data = 
+			zs_channels[n_channels].data =
 				zs_channels[n_channels].control + 4;
 
-#ifndef CONFIG_SERIAL_CONSOLE
+#ifndef CONFIG_SERIAL_DEC_CONSOLE
 			/*
 			 * We're called early and memory managment isn't up, yet.
 			 * Thus check_region would fail.
@@ -1729,20 +1697,24 @@ static void __init probe_sccs(void)
 				panic("SCC I/O region is not free");
 #endif
 			zs_soft[n_channels].zs_channel = &zs_channels[n_channels];
-			zs_soft[n_channels].irq = zs_parms->irq;
+			/* HACK alert! */
+			if (!(chip & 1))
+				zs_soft[n_channels].irq = zs_parms->irq0;
+			else
+				zs_soft[n_channels].irq = zs_parms->irq1;
 
-			/* 
+			/*
 			 *  Identification of channel A. Location of channel A
                          *  inside chip depends on mapping of internal address
 			 *  the chip decodes channels by.
-			 *  CHANNEL_A_NR returns either 0 (in case of 
+			 *  CHANNEL_A_NR returns either 0 (in case of
 			 *  DECstations) or 1 (in case of Baget).
 			 */
 			if (CHANNEL_A_NR == channel)
-				zs_soft[n_channels].zs_chan_a = 
+				zs_soft[n_channels].zs_chan_a =
 				    &zs_channels[n_channels+1-2*CHANNEL_A_NR];
 			else
-				zs_soft[n_channels].zs_chan_a = 
+				zs_soft[n_channels].zs_chan_a =
 				    &zs_channels[n_channels];
 
 			*pp = &zs_soft[n_channels];
@@ -1760,16 +1732,17 @@ static void __init probe_sccs(void)
 		}
 	}
 
-/*	save_and_cli(flags);
+	save_and_cli(flags);
 	for (n = 0; n < zs_channels_found; n++) {
-		if (((int)zs_channels[n].control & 0xf) == 1) {
+		if (n % 2 == 0) {
 			write_zsreg(zs_soft[n].zs_chan_a, R9, FHWRES);
-			mdelay(10);
+			udelay(10);
 			write_zsreg(zs_soft[n].zs_chan_a, R9, 0);
 		}
-		load_zsregs(zs_soft[n].zs_channel, zs_soft[n].zs_channel->curregs);
-	} 
-	restore_flags(flags); */
+		load_zsregs(zs_soft[n].zs_channel,
+			    zs_soft[n].zs_channel->curregs);
+	}
+	restore_flags(flags);
 }
 
 static struct tty_operations serial_ops = {
@@ -1797,7 +1770,6 @@ static struct tty_operations serial_ops 
 int __init zs_init(void)
 {
 	int channel, i;
-	unsigned long flags;
 	struct dec_serial *info;
 
 	if(!BUS_PRESENT)
@@ -1809,7 +1781,6 @@ int __init zs_init(void)
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
 		probe_sccs();
-
 	serial_driver = alloc_tty_driver(zs_channels_found);
 	if (!serial_driver)
 		return -ENOMEM;
@@ -1833,39 +1804,25 @@ int __init zs_init(void)
 	tty_set_operations(serial_driver, &serial_ops);
 
 	if (tty_register_driver(serial_driver))
-		panic("Couldn't register serial driver\n");
-
-	save_flags(flags); cli();
-
-	for (channel = 0; channel < zs_channels_found; ++channel) {
-		if (zs_soft[channel].hook &&
-		    zs_soft[channel].hook->init_channel)
-			(*zs_soft[channel].hook->init_channel)
-				(&zs_soft[channel]);
+		panic("Couldn't register serial driver");
 
-		zs_soft[channel].clk_divisor = 16;
-		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
+	for (info = zs_chain, i = 0; info; info = info->zs_next, i++) {
 
-		if (request_irq(zs_parms->irq, rs_interrupt, SA_SHIRQ,
-				"SCC", &zs_soft[channel]))
-			printk(KERN_ERR "decserial: can't get irq %d\n",
-			       zs_parms->irq);
-	}
+		/* Needed before interrupts are enabled. */
+		info->tty = 0;
+		info->x_char = 0;
 
-	for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
-	{
 		if (info->hook && info->hook->init_info) {
 			(*info->hook->init_info)(info);
 			continue;
 		}
+
 		info->magic = SERIAL_MAGIC;
 		info->port = (int) info->zs_channel->control;
 		info->line = i;
-		info->tty = 0;
 		info->custom_divisor = 16;
 		info->close_delay = 50;
 		info->closing_wait = 3000;
-		info->x_char = 0;
 		info->event = 0;
 		info->count = 0;
 		info->blocked_open = 0;
@@ -1873,94 +1830,83 @@ int __init zs_init(void)
 		info->tqueue.data = info;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
-		printk("ttyS%d at 0x%08x (irq = %d)", info->line,
-		       info->port, info->irq);
-		printk(" is a Z85C30 SCC\n");
+		printk("ttyS%02d at 0x%08x (irq = %d) is a Z85C30 SCC\n",
+		       info->line, info->port, info->irq);
 		tty_register_device(serial_driver, info->line, NULL);
+
 	}
 
-	restore_flags(flags);
+	for (channel = 0; channel < zs_channels_found; ++channel) {
+		zs_soft[channel].clk_divisor = 16;
+		zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
 
-	return 0;
-}
+		if (request_irq(zs_soft[channel].irq, rs_interrupt, SA_SHIRQ,
+				"scc", &zs_soft[channel]))
+			printk(KERN_ERR "decserial: can't get irq %d\n",
+			       zs_soft[channel].irq);
 
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
-	return -1;
-}
+		if (zs_soft[channel].hook) {
+			zs_startup(&zs_soft[channel]);
+			if (zs_soft[channel].hook->init_channel)
+				(*zs_soft[channel].hook->init_channel)
+					(&zs_soft[channel]);
+		}
+	}
 
-void unregister_serial(int line)
-{
-	return;
+	return 0;
 }
 
 /*
  * polling I/O routines
  */
 static int
-zs_poll_tx_char(struct dec_serial *info, unsigned char ch)
+zs_poll_tx_char(void *handle, unsigned char ch)
 {
+	struct dec_serial *info = handle;
 	struct dec_zschannel *chan = info->zs_channel;
 	int    ret;
 
 	if(chan) {
 		int loops = 10000;
-//		int nine = read_zsreg(chan, R9);
-
-		RECOVERY_DELAY;
-//        	write_zsreg(chan, R9, nine & ~MIE);
-               	wbflush();
-		RECOVERY_DELAY;
-
-        	while (!(*(chan->control) & Tx_BUF_EMP) && --loops)
-	        	RECOVERY_DELAY;
-
-                if (loops) {
-                        ret = 0;
-        	        *(chan->data) = ch;
-                	wbflush();
-			RECOVERY_DELAY;
-                } else
-                        ret = -EAGAIN;
 
-//        	write_zsreg(chan, R9, nine);
-               	wbflush();
-		RECOVERY_DELAY;
+		while (loops && !(read_zsreg(chan, 0) & Tx_BUF_EMP))
+			loops--;
 
-                return ret;
-        }
+		if (loops) {
+			write_zsdata(chan, ch);
+			ret = 0;
+		} else
+			ret = -EAGAIN;
 
-	return -ENODEV;
+		return ret;
+	} else
+		return -ENODEV;
 }
 
 static int
-zs_poll_rx_char(struct dec_serial *info)
+zs_poll_rx_char(void *handle)
 {
+	struct dec_serial *info = handle;
         struct dec_zschannel *chan = info->zs_channel;
         int    ret;
 
 	if(chan) {
                 int loops = 10000;
 
-                while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
-		        loops--;
+		while (loops && !(read_zsreg(chan, 0) & Rx_CH_AV))
+			loops--;
 
                 if (loops)
                         ret = read_zsdata(chan);
                 else
                         ret = -EAGAIN;
 
-                return ret;
-        } else
-                return -ENODEV;
+		return ret;
+	} else
+		return -ENODEV;
 }
 
-unsigned int register_zs_hook(unsigned int channel, struct zs_hook *hook)
+int register_zs_hook(unsigned int channel, struct dec_serial_hook *hook)
 {
 	struct dec_serial *info = &zs_soft[channel];
 
@@ -1970,22 +1916,15 @@ unsigned int register_zs_hook(unsigned i
 
 		return 0;
 	} else {
-		info->hook = hook;
-
-		if (zs_chain == 0)
-			probe_sccs();
-
-		if (!(info->flags & ZILOG_INITIALIZED))
-			zs_startup(info);
-
 		hook->poll_rx_char = zs_poll_rx_char;
 		hook->poll_tx_char = zs_poll_tx_char;
+		info->hook = hook;
 
 		return 1;
 	}
 }
 
-unsigned int unregister_zs_hook(unsigned int channel)
+int unregister_zs_hook(unsigned int channel)
 {
 	struct dec_serial *info = &zs_soft[channel];
 
@@ -2004,7 +1943,7 @@ unsigned int unregister_zs_hook(unsigned
  * Serial console driver
  * ------------------------------------------------------------
  */
-#ifdef CONFIG_SERIAL_CONSOLE
+#ifdef CONFIG_SERIAL_DEC_CONSOLE
 
 
 /*
@@ -2041,11 +1980,13 @@ static struct tty_driver *serial_console
 static int __init serial_console_setup(struct console *co, char *options)
 {
 	struct dec_serial *info;
-	int	baud = 9600;
-	int	bits = 8;
-	int	parity = 'n';
-	int	cflag = CREAD | HUPCL | CLOCAL;
-	char	*s;
+	int baud = 9600;
+	int bits = 8;
+	int parity = 'n';
+	int cflag = CREAD | HUPCL | CLOCAL;
+	int clk_divisor = 16;
+	int brg;
+	char *s;
 	unsigned long flags;
 
 	if(!BUS_PRESENT)
@@ -2097,6 +2038,10 @@ static int __init serial_console_setup(s
 	case 9600:
 	default:
 		cflag |= B9600;
+		/*
+		 * Set this to a sane value to prevent a divide error.
+		 */
+		baud  = 9600;
 		break;
 	}
 	switch(bits) {
@@ -2117,43 +2062,64 @@ static int __init serial_console_setup(s
 		break;
 	}
 	co->cflag = cflag;
-#if 1 
+
 	save_and_cli(flags);
 
 	/*
+	 * Set up the baud rate generator.
+	 */
+	brg = BPS_TO_BRG(baud, zs_parms->clock / clk_divisor);
+	info->zs_channel->curregs[R12] = (brg & 255);
+	info->zs_channel->curregs[R13] = ((brg >> 8) & 255);
+
+	/*
+	 * Set byte size and parity.
+	 */
+	if (bits == 7) {
+		info->zs_channel->curregs[R3] |= Rx7;
+		info->zs_channel->curregs[R5] |= Tx7;
+	} else {
+		info->zs_channel->curregs[R3] |= Rx8;
+		info->zs_channel->curregs[R5] |= Tx8;
+	}
+	if (cflag & PARENB) {
+		info->zs_channel->curregs[R4] |= PAR_ENA;
+	}
+	if (!(cflag & PARODD)) {
+		info->zs_channel->curregs[R4] |= PAR_EVEN;
+	}
+	info->zs_channel->curregs[R4] |= SB1;
+
+	/*
 	 * Turn on RTS and DTR.
 	 */
 	zs_rtsdtr(info, RTS | DTR, 1);
 
 	/*
-	 * Finally, enable sequencing
+	 * Finally, enable sequencing.
 	 */
-	info->zs_channel->curregs[3] |= (RxENABLE | Rx8);
-	info->zs_channel->curregs[5] |= (TxENAB | Tx8);
-	info->zs_channel->curregs[9] |= (VIS);
-	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);
-	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);
-	write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);
+	info->zs_channel->curregs[R3] |= RxENABLE;
+	info->zs_channel->curregs[R5] |= TxENAB;
 
 	/*
 	 * Clear the interrupt registers.
 	 */
-	write_zsreg(info->zs_channel, 0, ERR_RES);
-	write_zsreg(info->zs_channel, 0, RES_H_IUS);
+	write_zsreg(info->zs_channel, R0, ERR_RES);
+	write_zsreg(info->zs_channel, R0, RES_H_IUS);
 
 	/*
-	 * Set the speed of the serial port
+	 * Load up the new values.
 	 */
-	change_speed(info);
+	load_zsregs(info->zs_channel, info->zs_channel->curregs);
 
 	/* Save the current value of RR0 */
-	info->read_reg_zero = read_zsreg(info->zs_channel, 0);
+	info->read_reg_zero = read_zsreg(info->zs_channel, R0);
 
-	zs_soft[co->index].clk_divisor = 16;
+	zs_soft[co->index].clk_divisor = clk_divisor;
 	zs_soft[co->index].zs_baud = get_zsbaud(&zs_soft[co->index]);
 
 	restore_flags(flags);
-#endif
+
 	return 0;
 }
 
@@ -2173,7 +2139,7 @@ void __init zs_serial_console_init(void)
 {
 	register_console(&sercons);
 }
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
+#endif /* ifdef CONFIG_SERIAL_DEC_CONSOLE */
 
 #ifdef CONFIG_KGDB
 struct dec_zschannel *zs_kgdbchan;
@@ -2211,7 +2177,7 @@ void kgdb_interruptible(int yes)
 	int one, nine;
 	nine = read_zsreg(chan, 9);
 	if (yes == 1) {
-		one = EXT_INT_ENAB|INT_ALL_Rx;
+		one = EXT_INT_ENAB|RxINT_ALL;
 		nine |= MIE;
 		printk("turning serial ints on\n");
 	} else {
@@ -2223,22 +2189,23 @@ void kgdb_interruptible(int yes)
 	write_zsreg(chan, 9, nine);
 }
 
-static int kgdbhook_init_channel(struct dec_serial* info) 
+static int kgdbhook_init_channel(void *handle)
 {
 	return 0;
 }
 
-static void kgdbhook_init_info(struct dec_serial* info)
+static void kgdbhook_init_info(void *handle)
 {
 }
 
-static void kgdbhook_rx_char(struct dec_serial* info, 
-			     unsigned char ch, unsigned char stat)
+static void kgdbhook_rx_char(void *handle, unsigned char ch, unsigned char fl)
 {
+	struct dec_serial *info = handle;
+
+	if (fl != TTY_NORMAL)
+		return;
 	if (ch == 0x03 || ch == '$')
 		breakpoint();
-	if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
-		write_zsreg(info->zs_channel, 0, ERR_RES);
 }
 
 /* This sets up the serial port we're using, and turns on
@@ -2264,11 +2231,11 @@ static inline void kgdb_chaninit(struct 
  * for /dev/ttyb which is determined in setup_arch() from the
  * boot command line flags.
  */
-struct zs_hook zs_kgdbhook = {
-	init_channel : kgdbhook_init_channel,
-	init_info    : kgdbhook_init_info,
-	cflags       : B38400|CS8|CLOCAL,
-	rx_char      : kgdbhook_rx_char,
+struct dec_serial_hook zs_kgdbhook = {
+	.init_channel	= kgdbhook_init_channel,
+	.init_info	= kgdbhook_init_info,
+	.rx_char	= kgdbhook_rx_char,
+	.cflags		= B38400 | CS8 | CLOCAL,
 }
 
 void __init zs_kgdb_hook(int tty_num)
diff -puN drivers/tc/zs.h~mips-decstation-turbochannel-updates drivers/tc/zs.h
--- 25/drivers/tc/zs.h~mips-decstation-turbochannel-updates	2005-01-29 11:26:05.134967288 -0800
+++ 25-akpm/drivers/tc/zs.h	2005-01-29 11:26:05.147965312 -0800
@@ -1,14 +1,18 @@
 /*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
+ * drivers/tc/zs.h: Definitions for the DECstation Z85C30 serial driver.
  *
  * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
+ * Adapted from drivers/macintosh/macserial.h by Harald Koerfgen.
  *
  * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 2004  Maciej W. Rozycki
  */
 #ifndef _DECSERIAL_H
 #define _DECSERIAL_H
 
+#include <asm/dec/serial.h>
+
 #define NUM_ZSREGS    16
 
 struct serial_struct {
@@ -89,61 +93,48 @@ struct dec_zschannel {
 	unsigned char curregs[NUM_ZSREGS];
 };
 
-struct dec_serial;
-
-struct zs_hook {
-	int (*init_channel)(struct dec_serial* info);
-	void (*init_info)(struct dec_serial* info);
-	void (*rx_char)(unsigned char ch, unsigned char stat);
-	int  (*poll_rx_char)(struct dec_serial* info);
-	int  (*poll_tx_char)(struct dec_serial* info,
-			     unsigned char ch);
-	unsigned cflags;
-};
-
 struct dec_serial {
-	struct dec_serial *zs_next;	/* For IRQ servicing chain */
-	struct dec_zschannel *zs_channel; /* Channel registers */
-	struct dec_zschannel *zs_chan_a;	/* A side registers */
-	unsigned char read_reg_zero;
-
-	char soft_carrier;  /* Use soft carrier on this channel */
-	char break_abort;   /* Is serial console in, so process brk/abrt */
-	struct zs_hook *hook;  /* Hook on this channel */
-	char is_cons;       /* Is this our console. */
-	unsigned char tx_active; /* character is being xmitted */
-	unsigned char tx_stopped; /* output is suspended */
-
-	/* We need to know the current clock divisor
-	 * to read the bps rate the chip has currently
-	 * loaded.
+	struct dec_serial	*zs_next;	/* For IRQ servicing chain.  */
+	struct dec_zschannel	*zs_channel;	/* Channel registers.  */
+	struct dec_zschannel	*zs_chan_a;	/* A side registers.  */
+	unsigned char		read_reg_zero;
+
+	struct dec_serial_hook	*hook;		/* Hook on this channel.  */
+	int			tty_break;	/* Set on BREAK condition.  */
+	int			is_cons;	/* Is this our console.  */
+	int			tx_active;	/* Char is being xmitted.  */
+	int			tx_stopped;	/* Output is suspended.  */
+
+	/*
+	 * We need to know the current clock divisor
+	 * to read the bps rate the chip has currently loaded.
 	 */
-	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
-	int zs_baud;
+	int			clk_divisor;	/* May be 1, 16, 32, or 64.  */
+	int			zs_baud;
 
-	char change_needed;
+	char			change_needed;
 
 	int			magic;
 	int			baud_base;
 	int			port;
 	int			irq;
-	int			flags; 		/* defined in tty.h */
-	int			type; 		/* UART type */
+	int			flags; 		/* Defined in tty.h.  */
+	int			type; 		/* UART type.  */
 	struct tty_struct 	*tty;
 	int			read_status_mask;
 	int			ignore_status_mask;
 	int			timeout;
 	int			xmit_fifo_size;
 	int			custom_divisor;
-	int			x_char;	/* xon/xoff character */
+	int			x_char;		/* XON/XOFF character.  */
 	int			close_delay;
 	unsigned short		closing_wait;
 	unsigned short		closing_wait2;
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
-	int			count;	    /* # of fd on device */
-	int			blocked_open; /* # of blocked opens */
+	int			count;		/* # of fds on device.  */
+	int			blocked_open;	/* # of blocked opens.  */
 	unsigned char 		*xmit_buf;
 	int			xmit_head;
 	int			xmit_tail;
@@ -219,8 +210,9 @@ struct dec_serial {
 
 #define	RxINT_DISAB	0	/* Rx Int Disable */
 #define	RxINT_FCERR	0x8	/* Rx Int on First Character Only or Error */
-#define	INT_ALL_Rx	0x10	/* Int on all Rx Characters or error */
-#define	INT_ERR_Rx	0x18	/* Int on error only */
+#define	RxINT_ALL	0x10	/* Int on all Rx Characters or error */
+#define	RxINT_ERR	0x18	/* Int on error only */
+#define	RxINT_MASK	0x18
 
 #define	WT_RDY_RT	0x20	/* Wait/Ready on R/T */
 #define	WT_FN_RDYFN	0x40	/* Wait/FN/Ready FN */
_
