tty: move obsolete and broken generic_serial drivers to drivers/staging/generic_serial/

As planned by Arnd Bergmann, this moves the following drivers to the
drivers/staging/generic_serial directory where they will be removed
after 2.6.41 if no one steps up to claim them.
	generic_serial
	rio
	ser_a2232
	sx
	vme_scc

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: Jiri Slaby <jslaby@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index fb1fc4e..58e4a8e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -43,6 +43,8 @@
 
 source "drivers/staging/tty/Kconfig"
 
+source "drivers/staging/generic_serial/Kconfig"
+
 source "drivers/staging/et131x/Kconfig"
 
 source "drivers/staging/slicoss/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index f498e34..ff7372d 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -4,6 +4,7 @@
 obj-$(CONFIG_STAGING)		+= staging.o
 
 obj-y += tty/
+obj-y += generic_serial/
 obj-$(CONFIG_ET131X)		+= et131x/
 obj-$(CONFIG_SLICOSS)		+= slicoss/
 obj-$(CONFIG_VIDEO_GO7007)	+= go7007/
diff --git a/drivers/staging/generic_serial/Kconfig b/drivers/staging/generic_serial/Kconfig
new file mode 100644
index 0000000..795daea
--- /dev/null
+++ b/drivers/staging/generic_serial/Kconfig
@@ -0,0 +1,45 @@
+config A2232
+	tristate "Commodore A2232 serial support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && ZORRO && BROKEN
+	---help---
+	  This option supports the 2232 7-port serial card shipped with the
+	  Amiga 2000 and other Zorro-bus machines, dating from 1989.  At
+	  a max of 19,200 bps, the ports are served by a 6551 ACIA UART chip
+	  each, plus a 8520 CIA, and a master 6502 CPU and buffer as well. The
+	  ports were connected with 8 pin DIN connectors on the card bracket,
+	  for which 8 pin to DB25 adapters were supplied. The card also had
+	  jumpers internally to toggle various pinning configurations.
+
+	  This driver can be built as a module; but then "generic_serial"
+	  will also be built as a module. This has to be loaded before
+	  "ser_a2232". If you want to do this, answer M here.
+
+config SX
+	tristate "Specialix SX (and SI) card support"
+	depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) && BROKEN
+	help
+	  This is a driver for the SX and SI multiport serial cards.
+	  Please read the file <file:Documentation/serial/sx.txt> for details.
+
+	  This driver can only be built as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want).
+	  The module will be called sx. If you want to do that, say M here.
+
+config RIO
+	tristate "Specialix RIO system support"
+	depends on SERIAL_NONSTANDARD && BROKEN
+	help
+	  This is a driver for the Specialix RIO, a smart serial card which
+	  drives an outboard box that can support up to 128 ports.  Product
+	  information is at <http://www.perle.com/support/documentation.html#multiport>.
+	  There are both ISA and PCI versions.
+
+config RIO_OLDPCI
+	bool "Support really old RIO/PCI cards"
+	depends on RIO
+	help
+	  Older RIO PCI cards need some initialization-time configuration to
+	  determine the IRQ and some control addresses.  If you have a RIO and
+	  this doesn't seem to work, try setting this to Y.
+
+
diff --git a/drivers/staging/generic_serial/Makefile b/drivers/staging/generic_serial/Makefile
new file mode 100644
index 0000000..ffc90c8
--- /dev/null
+++ b/drivers/staging/generic_serial/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_MVME147_SCC)	+= generic_serial.o vme_scc.o
+obj-$(CONFIG_MVME162_SCC)	+= generic_serial.o vme_scc.o
+obj-$(CONFIG_BVME6000_SCC)	+= generic_serial.o vme_scc.o
+obj-$(CONFIG_A2232)		+= ser_a2232.o generic_serial.o
+obj-$(CONFIG_SX)		+= sx.o generic_serial.o
+obj-$(CONFIG_RIO)		+= rio/ generic_serial.o
diff --git a/drivers/staging/generic_serial/TODO b/drivers/staging/generic_serial/TODO
new file mode 100644
index 0000000..8875645
--- /dev/null
+++ b/drivers/staging/generic_serial/TODO
@@ -0,0 +1,6 @@
+These are a few tty/serial drivers that either do not build,
+or work if they do build, or if they seem to work, are for obsolete
+hardware, or are full of unfixable races and no one uses them anymore.
+
+If no one steps up to adopt any of these drivers, they will be removed
+in the 2.6.41 release.
diff --git a/drivers/staging/generic_serial/generic_serial.c b/drivers/staging/generic_serial/generic_serial.c
new file mode 100644
index 0000000..5954ee1
--- /dev/null
+++ b/drivers/staging/generic_serial/generic_serial.c
@@ -0,0 +1,844 @@
+/*
+ *  generic_serial.c
+ *
+ *  Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ *  written for the SX serial driver.
+ *     Contains the code that should be shared over all the serial drivers.
+ *
+ *  Credit for the idea to do it this way might go to Alan Cox. 
+ *
+ *
+ *  Version 0.1 -- December, 1998. Initial version.
+ *  Version 0.2 -- March, 1999.    Some more routines. Bugfixes. Etc.
+ *  Version 0.5 -- August, 1999.   Some more fixes. Reformat for Linus.
+ *
+ *  BitWizard is actively maintaining this file. We sometimes find
+ *  that someone submitted changes to this file. We really appreciate
+ *  your help, but please submit changes through us. We're doing our
+ *  best to be responsive.  -- REW
+ * */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+#include <linux/serial.h>
+#include <linux/mm.h>
+#include <linux/generic_serial.h>
+#include <linux/interrupt.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+#include <asm/uaccess.h>
+
+#define DEBUG 
+
+static int gs_debug;
+
+#ifdef DEBUG
+#define gs_dprintk(f, str...) if (gs_debug & f) printk (str)
+#else
+#define gs_dprintk(f, str...) /* nothing */
+#endif
+
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __func__)
+#define func_exit()  gs_dprintk (GS_DEBUG_FLOW, "gs: exit  %s\n", __func__)
+
+#define RS_EVENT_WRITE_WAKEUP	1
+
+module_param(gs_debug, int, 0644);
+
+
+int gs_put_char(struct tty_struct * tty, unsigned char ch)
+{
+	struct gs_port *port;
+
+	func_enter (); 
+
+	port = tty->driver_data;
+
+	if (!port) return 0;
+
+	if (! (port->port.flags & ASYNC_INITIALIZED)) return 0;
+
+	/* Take a lock on the serial tranmit buffer! */
+	mutex_lock(& port->port_write_mutex);
+
+	if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+		/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
+		mutex_unlock(&port->port_write_mutex);
+		return 0;
+	}
+
+	port->xmit_buf[port->xmit_head++] = ch;
+	port->xmit_head &= SERIAL_XMIT_SIZE - 1;
+	port->xmit_cnt++;  /* Characters in buffer */
+
+	mutex_unlock(&port->port_write_mutex);
+	func_exit ();
+	return 1;
+}
+
+
+/*
+> Problems to take into account are:
+>       -1- Interrupts that empty part of the buffer.
+>       -2- page faults on the access to userspace. 
+>       -3- Other processes that are also trying to do a "write". 
+*/
+
+int gs_write(struct tty_struct * tty, 
+                    const unsigned char *buf, int count)
+{
+	struct gs_port *port;
+	int c, total = 0;
+	int t;
+
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port) return 0;
+
+	if (! (port->port.flags & ASYNC_INITIALIZED))
+		return 0;
+
+	/* get exclusive "write" access to this port (problem 3) */
+	/* This is not a spinlock because we can have a disk access (page 
+		 fault) in copy_from_user */
+	mutex_lock(& port->port_write_mutex);
+
+	while (1) {
+
+		c = count;
+ 
+		/* This is safe because we "OWN" the "head". Noone else can 
+		   change the "head": we own the port_write_mutex. */
+		/* Don't overrun the end of the buffer */
+		t = SERIAL_XMIT_SIZE - port->xmit_head;
+		if (t < c) c = t;
+ 
+		/* This is safe because the xmit_cnt can only decrease. This 
+		   would increase "t", so we might copy too little chars. */
+		/* Don't copy past the "head" of the buffer */
+		t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+		if (t < c) c = t;
+ 
+		/* Can't copy more? break out! */
+		if (c <= 0) break;
+
+		memcpy (port->xmit_buf + port->xmit_head, buf, c);
+
+		port -> xmit_cnt += c;
+		port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+	mutex_unlock(& port->port_write_mutex);
+
+	gs_dprintk (GS_DEBUG_WRITE, "write: interrupts are %s\n", 
+	            (port->port.flags & GS_TX_INTEN)?"enabled": "disabled");
+
+	if (port->xmit_cnt && 
+	    !tty->stopped && 
+	    !tty->hw_stopped &&
+	    !(port->port.flags & GS_TX_INTEN)) {
+		port->port.flags |= GS_TX_INTEN;
+		port->rd->enable_tx_interrupts (port);
+	}
+	func_exit ();
+	return total;
+}
+
+
+
+int gs_write_room(struct tty_struct * tty)
+{
+	struct gs_port *port = tty->driver_data;
+	int ret;
+
+	func_enter ();
+	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	func_exit ();
+	return ret;
+}
+
+
+int gs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port = tty->driver_data;
+	func_enter ();
+
+	func_exit ();
+	return port->xmit_cnt;
+}
+
+
+static int gs_real_chars_in_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port;
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port->rd) return 0;
+	if (!port->rd->chars_in_buffer) return 0;
+
+	func_exit ();
+	return port->xmit_cnt + port->rd->chars_in_buffer (port);
+}
+
+
+static int gs_wait_tx_flushed (void * ptr, unsigned long timeout) 
+{
+	struct gs_port *port = ptr;
+	unsigned long end_jiffies;
+	int jiffies_to_transmit, charsleft = 0, rv = 0;
+	int rcib;
+
+	func_enter();
+
+	gs_dprintk (GS_DEBUG_FLUSH, "port=%p.\n", port);
+	if (port) {
+		gs_dprintk (GS_DEBUG_FLUSH, "xmit_cnt=%x, xmit_buf=%p, tty=%p.\n", 
+		port->xmit_cnt, port->xmit_buf, port->port.tty);
+	}
+
+	if (!port || port->xmit_cnt < 0 || !port->xmit_buf) {
+		gs_dprintk (GS_DEBUG_FLUSH, "ERROR: !port, !port->xmit_buf or prot->xmit_cnt < 0.\n");
+		func_exit();
+		return -EINVAL;  /* This is an error which we don't know how to handle. */
+	}
+
+	rcib = gs_real_chars_in_buffer(port->port.tty);
+
+	if(rcib <= 0) {
+		gs_dprintk (GS_DEBUG_FLUSH, "nothing to wait for.\n");
+		func_exit();
+		return rv;
+	}
+	/* stop trying: now + twice the time it would normally take +  seconds */
+	if (timeout == 0) timeout = MAX_SCHEDULE_TIMEOUT;
+	end_jiffies  = jiffies; 
+	if (timeout !=  MAX_SCHEDULE_TIMEOUT)
+		end_jiffies += port->baud?(2 * rcib * 10 * HZ / port->baud):0;
+	end_jiffies += timeout;
+
+	gs_dprintk (GS_DEBUG_FLUSH, "now=%lx, end=%lx (%ld).\n", 
+		    jiffies, end_jiffies, end_jiffies-jiffies); 
+
+	/* the expression is actually jiffies < end_jiffies, but that won't
+	   work around the wraparound. Tricky eh? */
+	while ((charsleft = gs_real_chars_in_buffer (port->port.tty)) &&
+	        time_after (end_jiffies, jiffies)) {
+		/* Units check: 
+		   chars * (bits/char) * (jiffies /sec) / (bits/sec) = jiffies!
+		   check! */
+
+		charsleft += 16; /* Allow 16 chars more to be transmitted ... */
+		jiffies_to_transmit = port->baud?(1 + charsleft * 10 * HZ / port->baud):0;
+		/*                                ^^^ Round up.... */
+		if (jiffies_to_transmit <= 0) jiffies_to_transmit = 1;
+
+		gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
+			    "(%d chars).\n", jiffies_to_transmit, charsleft); 
+
+		msleep_interruptible(jiffies_to_msecs(jiffies_to_transmit));
+		if (signal_pending (current)) {
+			gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: "); 
+			rv = -EINTR;
+			break;
+		}
+	}
+
+	gs_dprintk (GS_DEBUG_FLUSH, "charsleft = %d.\n", charsleft); 
+	set_current_state (TASK_RUNNING);
+
+	func_exit();
+	return rv;
+}
+
+
+
+void gs_flush_buffer(struct tty_struct *tty)
+{
+	struct gs_port *port;
+	unsigned long flags;
+
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port) return;
+
+	/* XXX Would the write semaphore do? */
+	spin_lock_irqsave (&port->driver_lock, flags);
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	spin_unlock_irqrestore (&port->driver_lock, flags);
+
+	tty_wakeup(tty);
+	func_exit ();
+}
+
+
+void gs_flush_chars(struct tty_struct * tty)
+{
+	struct gs_port *port;
+
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port) return;
+
+	if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !port->xmit_buf) {
+		func_exit ();
+		return;
+	}
+
+	/* Beats me -- REW */
+	port->port.flags |= GS_TX_INTEN;
+	port->rd->enable_tx_interrupts (port);
+	func_exit ();
+}
+
+
+void gs_stop(struct tty_struct * tty)
+{
+	struct gs_port *port;
+
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port) return;
+
+	if (port->xmit_cnt && 
+	    port->xmit_buf && 
+	    (port->port.flags & GS_TX_INTEN) ) {
+		port->port.flags &= ~GS_TX_INTEN;
+		port->rd->disable_tx_interrupts (port);
+	}
+	func_exit ();
+}
+
+
+void gs_start(struct tty_struct * tty)
+{
+	struct gs_port *port;
+
+	port = tty->driver_data;
+
+	if (!port) return;
+
+	if (port->xmit_cnt && 
+	    port->xmit_buf && 
+	    !(port->port.flags & GS_TX_INTEN) ) {
+		port->port.flags |= GS_TX_INTEN;
+		port->rd->enable_tx_interrupts (port);
+	}
+	func_exit ();
+}
+
+
+static void gs_shutdown_port (struct gs_port *port)
+{
+	unsigned long flags;
+
+	func_enter();
+	
+	if (!port) return;
+	
+	if (!(port->port.flags & ASYNC_INITIALIZED))
+		return;
+
+	spin_lock_irqsave(&port->driver_lock, flags);
+
+	if (port->xmit_buf) {
+		free_page((unsigned long) port->xmit_buf);
+		port->xmit_buf = NULL;
+	}
+
+	if (port->port.tty)
+		set_bit(TTY_IO_ERROR, &port->port.tty->flags);
+
+	port->rd->shutdown_port (port);
+
+	port->port.flags &= ~ASYNC_INITIALIZED;
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+
+	func_exit();
+}
+
+
+void gs_hangup(struct tty_struct *tty)
+{
+	struct gs_port *port;
+	unsigned long flags;
+
+	func_enter ();
+
+	port = tty->driver_data;
+	tty = port->port.tty;
+	if (!tty) 
+		return;
+
+	gs_shutdown_port (port);
+	spin_lock_irqsave(&port->port.lock, flags);
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE);
+	port->port.tty = NULL;
+	port->port.count = 0;
+	spin_unlock_irqrestore(&port->port.lock, flags);
+
+	wake_up_interruptible(&port->port.open_wait);
+	func_exit ();
+}
+
+
+int gs_block_til_ready(void *port_, struct file * filp)
+{
+	struct gs_port *gp = port_;
+	struct tty_port *port = &gp->port;
+	DECLARE_WAITQUEUE(wait, current);
+	int    retval;
+	int    do_clocal = 0;
+	int    CD;
+	struct tty_struct *tty;
+	unsigned long flags;
+
+	func_enter ();
+
+	if (!port) return 0;
+
+	tty = port->tty;
+
+	gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); 
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&port->close_wait);
+		if (port->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); 
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		port->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); 
+ 
+	if (C_CLOCAL(tty))
+		do_clocal = 1;
+
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, port->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+
+	add_wait_queue(&port->open_wait, &wait);
+
+	gs_dprintk (GS_DEBUG_BTR, "after add waitq.\n"); 
+	spin_lock_irqsave(&port->lock, flags);
+	if (!tty_hung_up_p(filp)) {
+		port->count--;
+	}
+	port->blocked_open++;
+	spin_unlock_irqrestore(&port->lock, flags);
+	while (1) {
+		CD = tty_port_carrier_raised(port);
+		gs_dprintk (GS_DEBUG_BTR, "CD is now %d.\n", CD);
+		set_current_state (TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(port->flags & ASYNC_INITIALIZED)) {
+			if (port->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;
+			break;
+		}
+		if (!(port->flags & ASYNC_CLOSING) &&
+		    (do_clocal || CD))
+			break;
+		gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", 
+		(int)signal_pending (current), *(long*)(&current->blocked)); 
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	gs_dprintk (GS_DEBUG_BTR, "Got out of the loop. (%d)\n",
+		    port->blocked_open);
+	set_current_state (TASK_RUNNING);
+	remove_wait_queue(&port->open_wait, &wait);
+	
+	spin_lock_irqsave(&port->lock, flags);
+	if (!tty_hung_up_p(filp)) {
+		port->count++;
+	}
+	port->blocked_open--;
+	if (retval == 0)
+        	port->flags |= ASYNC_NORMAL_ACTIVE;
+	spin_unlock_irqrestore(&port->lock, flags);
+	func_exit ();
+	return retval;
+}			 
+
+
+void gs_close(struct tty_struct * tty, struct file * filp)
+{
+	unsigned long flags;
+	struct gs_port *port;
+	
+	func_enter ();
+
+	port = tty->driver_data;
+
+	if (!port) return;
+
+	if (!port->port.tty) {
+		/* This seems to happen when this is called from vhangup. */
+		gs_dprintk (GS_DEBUG_CLOSE, "gs: Odd: port->port.tty is NULL\n");
+		port->port.tty = tty;
+	}
+
+	spin_lock_irqsave(&port->port.lock, flags);
+
+	if (tty_hung_up_p(filp)) {
+		spin_unlock_irqrestore(&port->port.lock, flags);
+		if (port->rd->hungup)
+			port->rd->hungup (port);
+		func_exit ();
+		return;
+	}
+
+	if ((tty->count == 1) && (port->port.count != 1)) {
+		printk(KERN_ERR "gs: gs_close port %p: bad port count;"
+		       " tty->count is 1, port count is %d\n", port, port->port.count);
+		port->port.count = 1;
+	}
+	if (--port->port.count < 0) {
+		printk(KERN_ERR "gs: gs_close port %p: bad port count: %d\n", port, port->port.count);
+		port->port.count = 0;
+	}
+
+	if (port->port.count) {
+		gs_dprintk(GS_DEBUG_CLOSE, "gs_close port %p: count: %d\n", port, port->port.count);
+		spin_unlock_irqrestore(&port->port.lock, flags);
+		func_exit ();
+		return;
+	}
+	port->port.flags |= ASYNC_CLOSING;
+
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	/* if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+	   tty_wait_until_sent(tty, port->closing_wait); */
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	spin_lock_irqsave(&port->driver_lock, flags);
+	port->rd->disable_rx_interrupts (port);
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+	spin_unlock_irqrestore(&port->port.lock, flags);
+
+	/* close has no way of returning "EINTR", so discard return value */
+	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		gs_wait_tx_flushed (port, port->closing_wait);
+
+	port->port.flags &= ~GS_ACTIVE;
+
+	gs_flush_buffer(tty);
+
+	tty_ldisc_flush(tty);
+	tty->closing = 0;
+
+	spin_lock_irqsave(&port->driver_lock, flags);
+	port->event = 0;
+	port->rd->close (port);
+	port->rd->shutdown_port (port);
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+
+	spin_lock_irqsave(&port->port.lock, flags);
+	port->port.tty = NULL;
+
+	if (port->port.blocked_open) {
+		if (port->close_delay) {
+			spin_unlock_irqrestore(&port->port.lock, flags);
+			msleep_interruptible(jiffies_to_msecs(port->close_delay));
+			spin_lock_irqsave(&port->port.lock, flags);
+		}
+		wake_up_interruptible(&port->port.open_wait);
+	}
+	port->port.flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED);
+	spin_unlock_irqrestore(&port->port.lock, flags);
+	wake_up_interruptible(&port->port.close_wait);
+
+	func_exit ();
+}
+
+
+void gs_set_termios (struct tty_struct * tty, 
+                     struct ktermios * old_termios)
+{
+	struct gs_port *port;
+	int baudrate, tmp, rv;
+	struct ktermios *tiosp;
+
+	func_enter();
+
+	port = tty->driver_data;
+
+	if (!port) return;
+	if (!port->port.tty) {
+		/* This seems to happen when this is called after gs_close. */
+		gs_dprintk (GS_DEBUG_TERMIOS, "gs: Odd: port->port.tty is NULL\n");
+		port->port.tty = tty;
+	}
+
+
+	tiosp = tty->termios;
+
+	if (gs_debug & GS_DEBUG_TERMIOS) {
+		gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
+	}
+
+	if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) {
+		if(tiosp->c_iflag != old_termios->c_iflag)  printk("c_iflag changed\n");
+		if(tiosp->c_oflag != old_termios->c_oflag)  printk("c_oflag changed\n");
+		if(tiosp->c_cflag != old_termios->c_cflag)  printk("c_cflag changed\n");
+		if(tiosp->c_lflag != old_termios->c_lflag)  printk("c_lflag changed\n");
+		if(tiosp->c_line  != old_termios->c_line)   printk("c_line changed\n");
+		if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
+	}
+
+	baudrate = tty_get_baud_rate(tty);
+
+	if ((tiosp->c_cflag & CBAUD) == B38400) {
+		if (     (port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			baudrate = 57600;
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			baudrate = 115200;
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
+			baudrate = 230400;
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
+			baudrate = 460800;
+		else if ((port->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)
+			baudrate = (port->baud_base / port->custom_divisor);
+	}
+
+	/* I recommend using THIS instead of the mess in termios (and
+	   duplicating the above code). Next we should create a clean
+	   interface towards this variable. If your card supports arbitrary
+	   baud rates, (e.g. CD1400 or 16550 based cards) then everything
+	   will be very easy..... */
+	port->baud = baudrate;
+
+	/* Two timer ticks seems enough to wakeup something like SLIP driver */
+	/* Baudrate/10 is cps. Divide by HZ to get chars per tick. */
+	tmp = (baudrate / 10 / HZ) * 2;			 
+
+	if (tmp <                 0) tmp = 0;
+	if (tmp >= SERIAL_XMIT_SIZE) tmp = SERIAL_XMIT_SIZE-1;
+
+	port->wakeup_chars = tmp;
+
+	/* We should really wait for the characters to be all sent before
+	   changing the settings. -- CAL */
+	rv = gs_wait_tx_flushed (port, MAX_SCHEDULE_TIMEOUT);
+	if (rv < 0) return /* rv */;
+
+	rv = port->rd->set_real_termios(port);
+	if (rv < 0) return /* rv */;
+
+	if ((!old_termios || 
+	     (old_termios->c_cflag & CRTSCTS)) &&
+	    !(      tiosp->c_cflag & CRTSCTS)) {
+		tty->stopped = 0;
+		gs_start(tty);
+	}
+
+#ifdef tytso_patch_94Nov25_1726
+	/* This "makes sense", Why is it commented out? */
+
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&port->gs.open_wait);
+#endif
+
+	func_exit();
+	return /* 0 */;
+}
+
+
+
+/* Must be called with interrupts enabled */
+int gs_init_port(struct gs_port *port)
+{
+	unsigned long flags;
+
+	func_enter ();
+
+	if (port->port.flags & ASYNC_INITIALIZED) {
+		func_exit ();
+		return 0;
+	}
+	if (!port->xmit_buf) {
+		/* We may sleep in get_zeroed_page() */
+		unsigned long tmp;
+
+		tmp = get_zeroed_page(GFP_KERNEL);
+		spin_lock_irqsave (&port->driver_lock, flags);
+		if (port->xmit_buf) 
+			free_page (tmp);
+		else
+			port->xmit_buf = (unsigned char *) tmp;
+		spin_unlock_irqrestore(&port->driver_lock, flags);
+		if (!port->xmit_buf) {
+			func_exit ();
+			return -ENOMEM;
+		}
+	}
+
+	spin_lock_irqsave (&port->driver_lock, flags);
+	if (port->port.tty)
+		clear_bit(TTY_IO_ERROR, &port->port.tty->flags);
+	mutex_init(&port->port_write_mutex);
+	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+	gs_set_termios(port->port.tty, NULL);
+	spin_lock_irqsave (&port->driver_lock, flags);
+	port->port.flags |= ASYNC_INITIALIZED;
+	port->port.flags &= ~GS_TX_INTEN;
+
+	spin_unlock_irqrestore(&port->driver_lock, flags);
+	func_exit ();
+	return 0;
+}
+
+
+int gs_setserial(struct gs_port *port, struct serial_struct __user *sp)
+{
+	struct serial_struct sio;
+
+	if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
+		return(-EFAULT);
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((sio.baud_base != port->baud_base) ||
+		    (sio.close_delay != port->close_delay) ||
+		    ((sio.flags & ~ASYNC_USR_MASK) !=
+		     (port->port.flags & ~ASYNC_USR_MASK)))
+			return(-EPERM);
+	} 
+
+	port->port.flags = (port->port.flags & ~ASYNC_USR_MASK) |
+		(sio.flags & ASYNC_USR_MASK);
+  
+	port->baud_base = sio.baud_base;
+	port->close_delay = sio.close_delay;
+	port->closing_wait = sio.closing_wait;
+	port->custom_divisor = sio.custom_divisor;
+
+	gs_set_termios (port->port.tty, NULL);
+
+	return 0;
+}
+
+
+/*****************************************************************************/
+
+/*
+ *      Generate the serial struct info.
+ */
+
+int gs_getserial(struct gs_port *port, struct serial_struct __user *sp)
+{
+	struct serial_struct    sio;
+
+	memset(&sio, 0, sizeof(struct serial_struct));
+	sio.flags = port->port.flags;
+	sio.baud_base = port->baud_base;
+	sio.close_delay = port->close_delay;
+	sio.closing_wait = port->closing_wait;
+	sio.custom_divisor = port->custom_divisor;
+	sio.hub6 = 0;
+
+	/* If you want you can override these. */
+	sio.type = PORT_UNKNOWN;
+	sio.xmit_fifo_size = -1;
+	sio.line = -1;
+	sio.port = -1;
+	sio.irq = -1;
+
+	if (port->rd->getserial)
+		port->rd->getserial (port, &sio);
+
+	if (copy_to_user(sp, &sio, sizeof(struct serial_struct)))
+		return -EFAULT;
+	return 0;
+
+}
+
+
+void gs_got_break(struct gs_port *port)
+{
+	func_enter ();
+
+	tty_insert_flip_char(port->port.tty, 0, TTY_BREAK);
+	tty_schedule_flip(port->port.tty);
+	if (port->port.flags & ASYNC_SAK) {
+		do_SAK (port->port.tty);
+	}
+
+	func_exit ();
+}
+
+
+EXPORT_SYMBOL(gs_put_char);
+EXPORT_SYMBOL(gs_write);
+EXPORT_SYMBOL(gs_write_room);
+EXPORT_SYMBOL(gs_chars_in_buffer);
+EXPORT_SYMBOL(gs_flush_buffer);
+EXPORT_SYMBOL(gs_flush_chars);
+EXPORT_SYMBOL(gs_stop);
+EXPORT_SYMBOL(gs_start);
+EXPORT_SYMBOL(gs_hangup);
+EXPORT_SYMBOL(gs_block_til_ready);
+EXPORT_SYMBOL(gs_close);
+EXPORT_SYMBOL(gs_set_termios);
+EXPORT_SYMBOL(gs_init_port);
+EXPORT_SYMBOL(gs_setserial);
+EXPORT_SYMBOL(gs_getserial);
+EXPORT_SYMBOL(gs_got_break);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/generic_serial/rio/Makefile b/drivers/staging/generic_serial/rio/Makefile
new file mode 100644
index 0000000..1661875
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux rio-subsystem.
+#
+# (C) R.E.Wolff@BitWizard.nl 
+# 
+# This file is GPL. See other files for the full Blurb. I'm lazy today. 
+#
+
+obj-$(CONFIG_RIO) += rio.o
+
+rio-y := rio_linux.o rioinit.o rioboot.o riocmd.o rioctrl.o riointr.o \
+            rioparam.o rioroute.o riotable.o riotty.o
diff --git a/drivers/staging/generic_serial/rio/board.h b/drivers/staging/generic_serial/rio/board.h
new file mode 100644
index 0000000..bdea633
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/board.h
@@ -0,0 +1,132 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources. 
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: board.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:07
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)board.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_board_h__
+#define	__rio_board_h__
+
+/*
+** board.h contains the definitions for the *hardware* of the host cards.
+** It describes the memory overlay for the dual port RAM area.
+*/
+
+#define	DP_SRAM1_SIZE	0x7C00
+#define	DP_SRAM2_SIZE	0x0200
+#define	DP_SRAM3_SIZE	0x7000
+#define	DP_SCRATCH_SIZE	0x1000
+#define	DP_PARMMAP_ADDR	0x01FE	/* offset into SRAM2 */
+#define	DP_STARTUP_ADDR	0x01F8	/* offset into SRAM2 */
+
+/*
+**	The shape of the Host Control area, at offset 0x7C00, Write Only
+*/
+struct s_Ctrl {
+	u8 DpCtl;		/* 7C00 */
+	u8 Dp_Unused2_[127];
+	u8 DpIntSet;		/* 7C80 */
+	u8 Dp_Unused3_[127];
+	u8 DpTpuReset;	/* 7D00 */
+	u8 Dp_Unused4_[127];
+	u8 DpIntReset;	/* 7D80 */
+	u8 Dp_Unused5_[127];
+};
+
+/*
+** The PROM data area on the host (0x7C00), Read Only
+*/
+struct s_Prom {
+	u16 DpSlxCode[2];
+	u16 DpRev;
+	u16 Dp_Unused6_;
+	u16 DpUniq[4];
+	u16 DpJahre;
+	u16 DpWoche;
+	u16 DpHwFeature[5];
+	u16 DpOemId;
+	u16 DpSiggy[16];
+};
+
+/*
+** Union of the Ctrl and Prom areas
+*/
+union u_CtrlProm {		/* This is the control/PROM area (0x7C00) */
+	struct s_Ctrl DpCtrl;
+	struct s_Prom DpProm;
+};
+
+/*
+** The top end of memory!
+*/
+struct s_ParmMapS {		/* Area containing Parm Map Pointer */
+	u8 Dp_Unused8_[DP_PARMMAP_ADDR];
+	u16 DpParmMapAd;
+};
+
+struct s_StartUpS {
+	u8 Dp_Unused9_[DP_STARTUP_ADDR];
+	u8 Dp_LongJump[0x4];
+	u8 Dp_Unused10_[2];
+	u8 Dp_ShortJump[0x2];
+};
+
+union u_Sram2ParmMap {		/* This is the top of memory (0x7E00-0x7FFF) */
+	u8 DpSramMem[DP_SRAM2_SIZE];
+	struct s_ParmMapS DpParmMapS;
+	struct s_StartUpS DpStartUpS;
+};
+
+/*
+**	This is the DP RAM overlay.
+*/
+struct DpRam {
+	u8 DpSram1[DP_SRAM1_SIZE];	/* 0000 - 7BFF */
+	union u_CtrlProm DpCtrlProm;	/* 7C00 - 7DFF */
+	union u_Sram2ParmMap DpSram2ParmMap;	/* 7E00 - 7FFF */
+	u8 DpScratch[DP_SCRATCH_SIZE];	/* 8000 - 8FFF */
+	u8 DpSram3[DP_SRAM3_SIZE];	/* 9000 - FFFF */
+};
+
+#define	DpControl	DpCtrlProm.DpCtrl.DpCtl
+#define	DpSetInt	DpCtrlProm.DpCtrl.DpIntSet
+#define	DpResetTpu	DpCtrlProm.DpCtrl.DpTpuReset
+#define	DpResetInt	DpCtrlProm.DpCtrl.DpIntReset
+
+#define	DpSlx		DpCtrlProm.DpProm.DpSlxCode
+#define	DpRevision	DpCtrlProm.DpProm.DpRev
+#define	DpUnique	DpCtrlProm.DpProm.DpUniq
+#define	DpYear		DpCtrlProm.DpProm.DpJahre
+#define	DpWeek		DpCtrlProm.DpProm.DpWoche
+#define	DpSignature	DpCtrlProm.DpProm.DpSiggy
+
+#define	DpParmMapR	DpSram2ParmMap.DpParmMapS.DpParmMapAd
+#define	DpSram2		DpSram2ParmMap.DpSramMem
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/cirrus.h b/drivers/staging/generic_serial/rio/cirrus.h
new file mode 100644
index 0000000..5ab5167
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/cirrus.h
@@ -0,0 +1,210 @@
+/****************************************************************************
+ *******                                                              *******
+ *******		CIRRUS.H				      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Jeremy Rolls
+ Date    : 3 Aug 1990
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _cirrus_h
+#define _cirrus_h 1
+
+/* Bit fields for particular registers shared with driver */
+
+/* COR1 - driver and RTA */
+#define RIOC_COR1_ODD		0x80	/* Odd parity */
+#define RIOC_COR1_EVEN		0x00	/* Even parity */
+#define RIOC_COR1_NOP		0x00	/* No parity */
+#define RIOC_COR1_FORCE		0x20	/* Force parity */
+#define RIOC_COR1_NORMAL	0x40	/* With parity */
+#define RIOC_COR1_1STOP		0x00	/* 1 stop bit */
+#define RIOC_COR1_15STOP	0x04	/* 1.5 stop bits */
+#define RIOC_COR1_2STOP		0x08	/* 2 stop bits */
+#define RIOC_COR1_5BITS		0x00	/* 5 data bits */
+#define RIOC_COR1_6BITS		0x01	/* 6 data bits */
+#define RIOC_COR1_7BITS		0x02	/* 7 data bits */
+#define RIOC_COR1_8BITS		0x03	/* 8 data bits */
+
+#define RIOC_COR1_HOST		0xef	/* Safe host bits */
+
+/* RTA only */
+#define RIOC_COR1_CINPCK	0x00	/* Check parity of received characters */
+#define RIOC_COR1_CNINPCK	0x10	/* Don't check parity */
+
+/* COR2 bits for both RTA and driver use */
+#define RIOC_COR2_IXANY		0x80	/* IXANY - any character is XON */
+#define RIOC_COR2_IXON		0x40	/* IXON - enable tx soft flowcontrol */
+#define RIOC_COR2_RTSFLOW	0x02	/* Enable tx hardware flow control */
+
+/* Additional driver bits */
+#define RIOC_COR2_HUPCL		0x20	/* Hang up on close */
+#define RIOC_COR2_CTSFLOW	0x04	/* Enable rx hardware flow control */
+#define RIOC_COR2_IXOFF		0x01	/* Enable rx software flow control */
+#define RIOC_COR2_DTRFLOW	0x08	/* Enable tx hardware flow control */
+
+/* RTA use only */
+#define RIOC_COR2_ETC		0x20	/* Embedded transmit options */
+#define RIOC_COR2_LOCAL		0x10	/* Local loopback mode */
+#define RIOC_COR2_REMOTE	0x08	/* Remote loopback mode */
+#define RIOC_COR2_HOST		0xc2	/* Safe host bits */
+
+/* COR3 - RTA use only */
+#define RIOC_COR3_SCDRNG	0x80	/* Enable special char detect for range */
+#define RIOC_COR3_SCD34		0x40	/* Special character detect for SCHR's 3 + 4 */
+#define RIOC_COR3_FCT		0x20	/* Flow control transparency */
+#define RIOC_COR3_SCD12		0x10	/* Special character detect for SCHR's 1 + 2 */
+#define RIOC_COR3_FIFO12	0x0c	/* 12 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO10	0x0a	/* 10 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO8		0x08	/* 8 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO6		0x06	/* 6 chars for receive FIFO threshold */
+
+#define RIOC_COR3_THRESHOLD	RIOC_COR3_FIFO8	/* MUST BE LESS THAN MCOR_THRESHOLD */
+
+#define RIOC_COR3_DEFAULT	(RIOC_COR3_FCT | RIOC_COR3_THRESHOLD)
+				/* Default bits for COR3 */
+
+/* COR4 driver and RTA use */
+#define RIOC_COR4_IGNCR		0x80	/* Throw away CR's on input */
+#define RIOC_COR4_ICRNL		0x40	/* Map CR -> NL on input */
+#define RIOC_COR4_INLCR		0x20	/* Map NL -> CR on input */
+#define RIOC_COR4_IGNBRK	0x10	/* Ignore Break */
+#define RIOC_COR4_NBRKINT	0x08	/* No interrupt on break (-BRKINT) */
+#define RIOC_COR4_RAISEMOD	0x01	/* Raise modem output lines on non-zero baud */
+
+
+/* COR4 driver only */
+#define RIOC_COR4_IGNPAR	0x04	/* IGNPAR (ignore characters with errors) */
+#define RIOC_COR4_PARMRK	0x02	/* PARMRK */
+
+#define RIOC_COR4_HOST		0xf8	/* Safe host bits */
+
+/* COR4 RTA only */
+#define RIOC_COR4_CIGNPAR	0x02	/* Thrown away bad characters */
+#define RIOC_COR4_CPARMRK	0x04	/* PARMRK characters */
+#define RIOC_COR4_CNPARMRK	0x03	/* Don't PARMRK */
+
+/* COR5 driver and RTA use */
+#define RIOC_COR5_ISTRIP	0x80	/* Strip input chars to 7 bits */
+#define RIOC_COR5_LNE		0x40	/* Enable LNEXT processing */
+#define RIOC_COR5_CMOE		0x20	/* Match good and errored characters */
+#define RIOC_COR5_ONLCR		0x02	/* NL -> CR NL on output */
+#define RIOC_COR5_OCRNL		0x01	/* CR -> NL on output */
+
+/*
+** Spare bits - these are not used in the CIRRUS registers, so we use
+** them to set various other features.
+*/
+/*
+** tstop and tbusy indication
+*/
+#define RIOC_COR5_TSTATE_ON	0x08	/* Turn on monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_OFF	0x04	/* Turn off monitoring of tbusy and tstop */
+/*
+** TAB3
+*/
+#define RIOC_COR5_TAB3		0x10	/* TAB3 mode */
+
+#define RIOC_COR5_HOST		0xc3	/* Safe host bits */
+
+/* CCSR */
+#define RIOC_CCSR_TXFLOFF	0x04	/* Tx is xoffed */
+
+/* MSVR1 */
+/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
+   RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
+   serial option.
+*/
+#define RIOC_MSVR1_CD		0x80	/* CD (DSR on Cirrus) */
+#define RIOC_MSVR1_RTS		0x40	/* RTS (CTS on Cirrus) */
+#define RIOC_MSVR1_RI		0x20	/* RI */
+#define RIOC_MSVR1_DTR		0x10	/* DTR (CD on Cirrus) */
+#define RIOC_MSVR1_CTS		0x01	/* CTS output pin (RTS on Cirrus) */
+/* Next two used to indicate state of tbusy and tstop to driver */
+#define RIOC_MSVR1_TSTOP	0x08	/* Set if port flow controlled */
+#define RIOC_MSVR1_TEMPTY	0x04	/* Set if port tx buffer empty */
+
+#define RIOC_MSVR1_HOST		0xf3	/* The bits the host wants */
+
+/* Defines for the subscripts of a CONFIG packet */
+#define RIOC_CONFIG_COR1	1	/* Option register 1 */
+#define RIOC_CONFIG_COR2	2	/* Option register 2 */
+#define RIOC_CONFIG_COR4	3	/* Option register 4 */
+#define RIOC_CONFIG_COR5	4	/* Option register 5 */
+#define RIOC_CONFIG_TXXON	5	/* Tx XON character */
+#define RIOC_CONFIG_TXXOFF	6	/* Tx XOFF character */
+#define RIOC_CONFIG_RXXON	7	/* Rx XON character */
+#define RIOC_CONFIG_RXXOFF	8	/* Rx XOFF character */
+#define RIOC_CONFIG_LNEXT	9	/* LNEXT character */
+#define RIOC_CONFIG_TXBAUD	10	/* Tx baud rate */
+#define RIOC_CONFIG_RXBAUD	11	/* Rx baud rate */
+
+#define RIOC_PRE_EMPTIVE	0x80	/* Pre-emptive bit in command field */
+
+/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
+   CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
+   be used 
+*/
+#define RIOC_OPEN		0x00	/* Open a port */
+#define RIOC_CONFIG		0x01	/* Configure a port */
+#define RIOC_MOPEN		0x02	/* Modem open (block for DCD) */
+#define RIOC_CLOSE		0x03	/* Close a port */
+#define RIOC_WFLUSH		(0x04 | RIOC_PRE_EMPTIVE)	/* Write flush */
+#define RIOC_RFLUSH		(0x05 | RIOC_PRE_EMPTIVE)	/* Read flush */
+#define RIOC_RESUME		(0x06 | RIOC_PRE_EMPTIVE)	/* Resume if xoffed */
+#define RIOC_SBREAK		0x07	/* Start break */
+#define RIOC_EBREAK		0x08	/* End break */
+#define RIOC_SUSPEND		(0x09 | RIOC_PRE_EMPTIVE)	/* Susp op (behave as tho xoffed) */
+#define RIOC_FCLOSE		(0x0a | RIOC_PRE_EMPTIVE)	/* Force close */
+#define RIOC_XPRINT		0x0b	/* Xprint packet */
+#define RIOC_MBIS		(0x0c | RIOC_PRE_EMPTIVE)	/* Set modem lines */
+#define RIOC_MBIC		(0x0d | RIOC_PRE_EMPTIVE)	/* Clear modem lines */
+#define RIOC_MSET		(0x0e | RIOC_PRE_EMPTIVE)	/* Set modem lines */
+#define RIOC_PCLOSE		0x0f	/* Pseudo close - Leaves rx/tx enabled */
+#define RIOC_MGET		(0x10 | RIOC_PRE_EMPTIVE)	/* Force update of modem status */
+#define RIOC_MEMDUMP		(0x11 | RIOC_PRE_EMPTIVE)	/* Send back mem from addr supplied */
+#define RIOC_READ_REGISTER	(0x12 | RIOC_PRE_EMPTIVE)	/* Read CD1400 register (debug) */
+
+/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
+   use data[4] / data[3] to indicate current state and modem status respectively
+*/
+
+#define RIOC_COMPLETE		(0x20 | RIOC_PRE_EMPTIVE)
+				/* Command complete */
+#define RIOC_BREAK_RECEIVED	(0x21 | RIOC_PRE_EMPTIVE)
+				/* Break received */
+#define RIOC_MODEM_STATUS	(0x22 | RIOC_PRE_EMPTIVE)
+				/* Change in modem status */
+
+/* "Command" packet that could go either way - handshake wake-up */
+#define RIOC_HANDSHAKE		(0x23 | RIOC_PRE_EMPTIVE)
+				/* Wake-up to HOST / RTA */
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/cmdblk.h b/drivers/staging/generic_serial/rio/cmdblk.h
new file mode 100644
index 0000000..9ed4f86
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/cmdblk.h
@@ -0,0 +1,53 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: cmdblk.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdblk.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_cmdblk_h__
+#define __rio_cmdblk_h__
+
+/*
+** the structure of a command block, used to queue commands destined for
+** a rup.
+*/
+
+struct CmdBlk {
+	struct CmdBlk *NextP;	/* Pointer to next command block */
+	struct PKT Packet;	/* A packet, to copy to the rup */
+	/* The func to call to check if OK */
+	int (*PreFuncP) (unsigned long, struct CmdBlk *);
+	int PreArg;		/* The arg for the func */
+	/* The func to call when completed */
+	int (*PostFuncP) (unsigned long, struct CmdBlk *);
+	int PostArg;		/* The arg for the func */
+};
+
+#define NUM_RIO_CMD_BLKS (3 * (MAX_RUP * 4 + LINKS_PER_UNIT * 4))
+#endif
diff --git a/drivers/staging/generic_serial/rio/cmdpkt.h b/drivers/staging/generic_serial/rio/cmdpkt.h
new file mode 100644
index 0000000..c1e7a27
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/cmdpkt.h
@@ -0,0 +1,177 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: cmdpkt.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:20
+**
+**  ident @(#)cmdpkt.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+#ifndef __rio_cmdpkt_h__
+#define __rio_cmdpkt_h__
+
+/*
+** overlays for the data area of a packet. Used in both directions
+** (to build a packet to send, and to interpret a packet that arrives)
+** and is very inconvenient for MIPS, so they appear as two separate
+** structures - those used for modifying/reading packets on the card
+** and those for modifying/reading packets in real memory, which have an _M
+** suffix.
+*/
+
+#define	RTA_BOOT_DATA_SIZE (PKT_MAX_DATA_LEN-2)
+
+/*
+** The boot information packet looks like this:
+** This structure overlays a PktCmd->CmdData structure, and so starts
+** at Data[2] in the actual pkt!
+*/
+struct BootSequence {
+	u16 NumPackets;
+	u16 LoadBase;
+	u16 CodeSize;
+};
+
+#define	BOOT_SEQUENCE_LEN	8
+
+struct SamTop {
+	u8 Unit;
+	u8 Link;
+};
+
+struct CmdHdr {
+	u8 PcCommand;
+	union {
+		u8 PcPhbNum;
+		u8 PcLinkNum;
+		u8 PcIDNum;
+	} U0;
+};
+
+
+struct PktCmd {
+	union {
+		struct {
+			struct CmdHdr CmdHdr;
+			struct BootSequence PcBootSequence;
+		} S1;
+		struct {
+			u16 PcSequence;
+			u8 PcBootData[RTA_BOOT_DATA_SIZE];
+		} S2;
+		struct {
+			u16 __crud__;
+			u8 PcUniqNum[4];	/* this is really a uint. */
+			u8 PcModuleTypes;	/* what modules are fitted */
+		} S3;
+		struct {
+			struct CmdHdr CmdHdr;
+			u8 __undefined__;
+			u8 PcModemStatus;
+			u8 PcPortStatus;
+			u8 PcSubCommand;	/* commands like mem or register dump */
+			u16 PcSubAddr;	/* Address for command */
+			u8 PcSubData[64];	/* Date area for command */
+		} S4;
+		struct {
+			struct CmdHdr CmdHdr;
+			u8 PcCommandText[1];
+			u8 __crud__[20];
+			u8 PcIDNum2;	/* It had to go somewhere! */
+		} S5;
+		struct {
+			struct CmdHdr CmdHdr;
+			struct SamTop Topology[LINKS_PER_UNIT];
+		} S6;
+	} U1;
+};
+
+struct PktCmd_M {
+	union {
+		struct {
+			struct {
+				u8 PcCommand;
+				union {
+					u8 PcPhbNum;
+					u8 PcLinkNum;
+					u8 PcIDNum;
+				} U0;
+			} CmdHdr;
+			struct {
+				u16 NumPackets;
+				u16 LoadBase;
+				u16 CodeSize;
+			} PcBootSequence;
+		} S1;
+		struct {
+			u16 PcSequence;
+			u8 PcBootData[RTA_BOOT_DATA_SIZE];
+		} S2;
+		struct {
+			u16 __crud__;
+			u8 PcUniqNum[4];	/* this is really a uint. */
+			u8 PcModuleTypes;	/* what modules are fitted */
+		} S3;
+		struct {
+			u16 __cmd_hdr__;
+			u8 __undefined__;
+			u8 PcModemStatus;
+			u8 PcPortStatus;
+			u8 PcSubCommand;
+			u16 PcSubAddr;
+			u8 PcSubData[64];
+		} S4;
+		struct {
+			u16 __cmd_hdr__;
+			u8 PcCommandText[1];
+			u8 __crud__[20];
+			u8 PcIDNum2;	/* Tacked on end */
+		} S5;
+		struct {
+			u16 __cmd_hdr__;
+			struct Top Topology[LINKS_PER_UNIT];
+		} S6;
+	} U1;
+};
+
+#define Command		U1.S1.CmdHdr.PcCommand
+#define PhbNum		U1.S1.CmdHdr.U0.PcPhbNum
+#define IDNum		U1.S1.CmdHdr.U0.PcIDNum
+#define IDNum2		U1.S5.PcIDNum2
+#define LinkNum		U1.S1.CmdHdr.U0.PcLinkNum
+#define Sequence	U1.S2.PcSequence
+#define BootData	U1.S2.PcBootData
+#define BootSequence	U1.S1.PcBootSequence
+#define UniqNum		U1.S3.PcUniqNum
+#define ModemStatus	U1.S4.PcModemStatus
+#define PortStatus	U1.S4.PcPortStatus
+#define SubCommand	U1.S4.PcSubCommand
+#define SubAddr		U1.S4.PcSubAddr
+#define SubData		U1.S4.PcSubData
+#define CommandText	U1.S5.PcCommandText
+#define RouteTopology	U1.S6.Topology
+#define ModuleTypes	U1.S3.PcModuleTypes
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/daemon.h b/drivers/staging/generic_serial/rio/daemon.h
new file mode 100644
index 0000000..4af9032
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/daemon.h
@@ -0,0 +1,307 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: daemon.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:09
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)daemon.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_daemon_h__
+#define	__rio_daemon_h__
+
+
+/*
+** structures used on /dev/rio
+*/
+
+struct Error {
+	unsigned int Error;
+	unsigned int Entry;
+	unsigned int Other;
+};
+
+struct DownLoad {
+	char __user *DataP;
+	unsigned int Count;
+	unsigned int ProductCode;
+};
+
+/*
+** A few constants....
+*/
+#ifndef MAX_VERSION_LEN
+#define	MAX_VERSION_LEN	256
+#endif
+
+#ifndef MAX_XP_CTRL_LEN
+#define	MAX_XP_CTRL_LEN 16	/* ALSO IN PORT.H */
+#endif
+
+struct PortSetup {
+	unsigned int From;		/* Set/Clear XP & IXANY Control from this port.... */
+	unsigned int To;		/* .... to this port */
+	unsigned int XpCps;		/* at this speed */
+	char XpOn[MAX_XP_CTRL_LEN];	/* this is the start string */
+	char XpOff[MAX_XP_CTRL_LEN];	/* this is the stop string */
+	u8 IxAny;			/* enable/disable IXANY */
+	u8 IxOn;			/* enable/disable IXON */
+	u8 Lock;			/* lock port params */
+	u8 Store;			/* store params across closes */
+	u8 Drain;			/* close only when drained */
+};
+
+struct LpbReq {
+	unsigned int Host;
+	unsigned int Link;
+	struct LPB __user *LpbP;
+};
+
+struct RupReq {
+	unsigned int HostNum;
+	unsigned int RupNum;
+	struct RUP __user *RupP;
+};
+
+struct PortReq {
+	unsigned int SysPort;
+	struct Port __user *PortP;
+};
+
+struct StreamInfo {
+	unsigned int SysPort;
+	int RQueue;
+	int WQueue;
+};
+
+struct HostReq {
+	unsigned int HostNum;
+	struct Host __user *HostP;
+};
+
+struct HostDpRam {
+	unsigned int HostNum;
+	struct DpRam __user *DpRamP;
+};
+
+struct DebugCtrl {
+	unsigned int SysPort;
+	unsigned int Debug;
+	unsigned int Wait;
+};
+
+struct MapInfo {
+	unsigned int FirstPort;		/* 8 ports, starting from this (tty) number */
+	unsigned int RtaUnique;		/* reside on this RTA (unique number) */
+};
+
+struct MapIn {
+	unsigned int NumEntries;	/* How many port sets are we mapping? */
+	struct MapInfo *MapInfoP;	/* Pointer to (user space) info */
+};
+
+struct SendPack {
+	unsigned int PortNum;
+	unsigned char Len;
+	unsigned char Data[PKT_MAX_DATA_LEN];
+};
+
+struct SpecialRupCmd {
+	struct PKT Packet;
+	unsigned short Host;
+	unsigned short RupNum;
+};
+
+struct IdentifyRta {
+	unsigned long RtaUnique;
+	u8 ID;
+};
+
+struct KillNeighbour {
+	unsigned long UniqueNum;
+	u8 Link;
+};
+
+struct rioVersion {
+	char version[MAX_VERSION_LEN];
+	char relid[MAX_VERSION_LEN];
+	int buildLevel;
+	char buildDate[MAX_VERSION_LEN];
+};
+
+
+/*
+**	RIOC commands are for the daemon type operations
+**
+** 09.12.1998 ARG - ESIL 0776 part fix
+** Definition for 'RIOC' also appears in rioioctl.h, so we'd better do a
+** #ifndef here first.
+** rioioctl.h also now has #define 'RIO_QUICK_CHECK' as this ioctl is now
+** allowed to be used by customers.
+*/
+#ifndef RIOC
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+#endif
+
+/*
+** Boot stuff
+*/
+#define	RIO_GET_TABLE     (RIOC | 100)
+#define RIO_PUT_TABLE     (RIOC | 101)
+#define RIO_ASSIGN_RTA    (RIOC | 102)
+#define RIO_DELETE_RTA    (RIOC | 103)
+#define	RIO_HOST_FOAD	  (RIOC | 104)
+#define	RIO_QUICK_CHECK	  (RIOC | 105)
+#define RIO_SIGNALS_ON    (RIOC | 106)
+#define RIO_SIGNALS_OFF   (RIOC | 107)
+#define	RIO_CHANGE_NAME   (RIOC | 108)
+#define RIO_DOWNLOAD      (RIOC | 109)
+#define	RIO_GET_LOG	  (RIOC | 110)
+#define	RIO_SETUP_PORTS   (RIOC | 111)
+#define RIO_ALL_MODEM     (RIOC | 112)
+
+/*
+** card state, debug stuff
+*/
+#define	RIO_NUM_HOSTS	  (RIOC | 120)
+#define	RIO_HOST_LPB	  (RIOC | 121)
+#define	RIO_HOST_RUP	  (RIOC | 122)
+#define	RIO_HOST_PORT	  (RIOC | 123)
+#define	RIO_PARMS 	  (RIOC | 124)
+#define RIO_HOST_REQ	  (RIOC | 125)
+#define	RIO_READ_CONFIG	  (RIOC | 126)
+#define	RIO_SET_CONFIG	  (RIOC | 127)
+#define	RIO_VERSID	  (RIOC | 128)
+#define	RIO_FLAGS	  (RIOC | 129)
+#define	RIO_SETDEBUG	  (RIOC | 130)
+#define	RIO_GETDEBUG	  (RIOC | 131)
+#define	RIO_READ_LEVELS   (RIOC | 132)
+#define	RIO_SET_FAST_BUS  (RIOC | 133)
+#define	RIO_SET_SLOW_BUS  (RIOC | 134)
+#define	RIO_SET_BYTE_MODE (RIOC | 135)
+#define	RIO_SET_WORD_MODE (RIOC | 136)
+#define RIO_STREAM_INFO   (RIOC | 137)
+#define	RIO_START_POLLER  (RIOC | 138)
+#define	RIO_STOP_POLLER   (RIOC | 139)
+#define	RIO_LAST_ERROR    (RIOC | 140)
+#define	RIO_TICK	  (RIOC | 141)
+#define	RIO_TOCK	  (RIOC | 241)	/* I did this on purpose, you know. */
+#define	RIO_SEND_PACKET   (RIOC | 142)
+#define	RIO_SET_BUSY	  (RIOC | 143)
+#define	SPECIAL_RUP_CMD   (RIOC | 144)
+#define	RIO_FOAD_RTA      (RIOC | 145)
+#define	RIO_ZOMBIE_RTA    (RIOC | 146)
+#define RIO_IDENTIFY_RTA  (RIOC | 147)
+#define RIO_KILL_NEIGHBOUR (RIOC | 148)
+#define RIO_DEBUG_MEM     (RIOC | 149)
+/*
+** 150 - 167 used.....   See below
+*/
+#define RIO_GET_PORT_SETUP (RIOC | 168)
+#define RIO_RESUME        (RIOC | 169)
+#define	RIO_MESG	(RIOC | 170)
+#define	RIO_NO_MESG	(RIOC | 171)
+#define	RIO_WHAT_MESG	(RIOC | 172)
+#define RIO_HOST_DPRAM	(RIOC | 173)
+#define RIO_MAP_B50_TO_50	(RIOC | 174)
+#define RIO_MAP_B50_TO_57600	(RIOC | 175)
+#define RIO_MAP_B110_TO_110	(RIOC | 176)
+#define RIO_MAP_B110_TO_115200	(RIOC | 177)
+#define RIO_GET_PORT_PARAMS	(RIOC | 178)
+#define RIO_SET_PORT_PARAMS	(RIOC | 179)
+#define RIO_GET_PORT_TTY	(RIOC | 180)
+#define RIO_SET_PORT_TTY	(RIOC | 181)
+#define RIO_SYSLOG_ONLY	(RIOC | 182)
+#define RIO_SYSLOG_CONS	(RIOC | 183)
+#define RIO_CONS_ONLY	(RIOC | 184)
+#define RIO_BLOCK_OPENS	(RIOC | 185)
+
+/*
+** 02.03.1999 ARG - ESIL 0820 fix :
+** RIOBootMode is no longer use by the driver, so these ioctls
+** are now obsolete :
+**
+#define RIO_GET_BOOT_MODE	(RIOC | 186)
+#define RIO_SET_BOOT_MODE	(RIOC | 187)
+**
+*/
+
+#define RIO_MEM_DUMP	(RIOC | 189)
+#define RIO_READ_REGISTER	(RIOC | 190)
+#define RIO_GET_MODTYPE	(RIOC | 191)
+#define RIO_SET_TIMER	(RIOC | 192)
+#define RIO_READ_CHECK	(RIOC | 196)
+#define RIO_WAITING_FOR_RESTART	(RIOC | 197)
+#define RIO_BIND_RTA	(RIOC | 198)
+#define RIO_GET_BINDINGS	(RIOC | 199)
+#define RIO_PUT_BINDINGS	(RIOC | 200)
+
+#define	RIO_MAKE_DEV		(RIOC | 201)
+#define	RIO_MINOR		(RIOC | 202)
+
+#define	RIO_IDENTIFY_DRIVER	(RIOC | 203)
+#define	RIO_DISPLAY_HOST_CFG	(RIOC | 204)
+
+
+/*
+** MAKE_DEV / MINOR stuff
+*/
+#define	RIO_DEV_DIRECT		0x0000
+#define	RIO_DEV_MODEM		0x0200
+#define	RIO_DEV_XPRINT		0x0400
+#define	RIO_DEV_MASK		0x0600
+
+/*
+** port management, xprint stuff
+*/
+#define	rIOCN(N)	(RIOC|(N))
+#define	rIOCR(N,T)	(RIOC|(N))
+#define	rIOCW(N,T)	(RIOC|(N))
+
+#define	RIO_GET_XP_ON     rIOCR(150,char[16])	/* start xprint string */
+#define	RIO_SET_XP_ON     rIOCW(151,char[16])
+#define	RIO_GET_XP_OFF    rIOCR(152,char[16])	/* finish xprint string */
+#define	RIO_SET_XP_OFF    rIOCW(153,char[16])
+#define	RIO_GET_XP_CPS    rIOCR(154,int)	/* xprint CPS */
+#define	RIO_SET_XP_CPS    rIOCW(155,int)
+#define RIO_GET_IXANY     rIOCR(156,int)	/* ixany allowed? */
+#define RIO_SET_IXANY     rIOCW(157,int)
+#define RIO_SET_IXANY_ON  rIOCN(158)	/* allow ixany */
+#define RIO_SET_IXANY_OFF rIOCN(159)	/* disallow ixany */
+#define RIO_GET_MODEM     rIOCR(160,int)	/* port is modem/direct line? */
+#define RIO_SET_MODEM     rIOCW(161,int)
+#define RIO_SET_MODEM_ON  rIOCN(162)	/* port is a modem */
+#define RIO_SET_MODEM_OFF rIOCN(163)	/* port is direct */
+#define RIO_GET_IXON      rIOCR(164,int)	/* ixon allowed? */
+#define RIO_SET_IXON      rIOCW(165,int)
+#define RIO_SET_IXON_ON   rIOCN(166)	/* allow ixon */
+#define RIO_SET_IXON_OFF  rIOCN(167)	/* disallow ixon */
+
+#define RIO_GET_SIVIEW	  ((('s')<<8) | 106)	/* backwards compatible with SI */
+
+#define	RIO_IOCTL_UNKNOWN	-2
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/errors.h b/drivers/staging/generic_serial/rio/errors.h
new file mode 100644
index 0000000..bdb0523
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/errors.h
@@ -0,0 +1,98 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: errors.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)errors.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_errors_h__
+#define	__rio_errors_h__
+
+/*
+** error codes
+*/
+
+#define	NOTHING_WRONG_AT_ALL		0
+#define	BAD_CHARACTER_IN_NAME		1
+#define	TABLE_ENTRY_ISNT_PROPERLY_NULL	2
+#define	UNKNOWN_HOST_NUMBER		3
+#define	ZERO_RTA_ID			4
+#define	BAD_RTA_ID			5
+#define	DUPLICATED_RTA_ID		6
+#define	DUPLICATE_UNIQUE_NUMBER		7
+#define	BAD_TTY_NUMBER			8
+#define	TTY_NUMBER_IN_USE		9
+#define	NAME_USED_TWICE			10
+#define	HOST_ID_NOT_ZERO		11
+#define	BOOT_IN_PROGRESS		12
+#define	COPYIN_FAILED			13
+#define	HOST_FILE_TOO_LARGE		14
+#define	COPYOUT_FAILED			15
+#define	NOT_SUPER_USER			16
+#define	RIO_ALREADY_POLLING		17
+
+#define	ID_NUMBER_OUT_OF_RANGE		18
+#define PORT_NUMBER_OUT_OF_RANGE	19
+#define	HOST_NUMBER_OUT_OF_RANGE	20
+#define	RUP_NUMBER_OUT_OF_RANGE		21
+#define	TTY_NUMBER_OUT_OF_RANGE		22
+#define	LINK_NUMBER_OUT_OF_RANGE	23
+
+#define	HOST_NOT_RUNNING		24
+#define	IOCTL_COMMAND_UNKNOWN		25
+#define	RIO_SYSTEM_HALTED		26
+#define	WAIT_FOR_DRAIN_BROKEN		27
+#define	PORT_NOT_MAPPED_INTO_SYSTEM	28
+#define	EXCLUSIVE_USE_SET		29
+#define	WAIT_FOR_NOT_CLOSING_BROKEN	30
+#define	WAIT_FOR_PORT_TO_OPEN_BROKEN	31
+#define	WAIT_FOR_CARRIER_BROKEN		32
+#define	WAIT_FOR_NOT_IN_USE_BROKEN	33
+#define	WAIT_FOR_CAN_ADD_COMMAND_BROKEN	34
+#define	WAIT_FOR_ADD_COMMAND_BROKEN	35
+#define	WAIT_FOR_NOT_PARAM_BROKEN	36
+#define	WAIT_FOR_RETRY_BROKEN		37
+#define	HOST_HAS_ALREADY_BEEN_BOOTED	38
+#define	UNIT_IS_IN_USE			39
+#define	COULDNT_FIND_ENTRY		40
+#define	RTA_UNIQUE_NUMBER_ZERO		41
+#define	CLOSE_COMMAND_FAILED		42
+#define	WAIT_FOR_CLOSE_BROKEN		43
+#define	CPS_VALUE_OUT_OF_RANGE		44
+#define	ID_ALREADY_IN_USE		45
+#define	SIGNALS_ALREADY_SET		46
+#define	NOT_RECEIVING_PROCESS		47
+#define	RTA_NUMBER_WRONG		48
+#define NO_SUCH_PRODUCT			49
+#define	HOST_SYSPORT_BAD		50
+#define	ID_NOT_TENTATIVE		51
+#define XPRINT_CPS_OUT_OF_RANGE		52
+#define	NOT_ENOUGH_CORE_FOR_PCI_COPY	53
+
+
+#endif				/* __rio_errors_h__ */
diff --git a/drivers/staging/generic_serial/rio/func.h b/drivers/staging/generic_serial/rio/func.h
new file mode 100644
index 0000000..078d44f
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/func.h
@@ -0,0 +1,143 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: func.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)func.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __func_h_def
+#define __func_h_def
+
+#include <linux/kdev_t.h>
+
+/* rioboot.c */
+int RIOBootCodeRTA(struct rio_info *, struct DownLoad *);
+int RIOBootCodeHOST(struct rio_info *, struct DownLoad *);
+int RIOBootCodeUNKNOWN(struct rio_info *, struct DownLoad *);
+void msec_timeout(struct Host *);
+int RIOBootRup(struct rio_info *, unsigned int, struct Host *, struct PKT __iomem *);
+int RIOBootOk(struct rio_info *, struct Host *, unsigned long);
+int RIORtaBound(struct rio_info *, unsigned int);
+void rio_fill_host_slot(int, int, unsigned int, struct Host *);
+
+/* riocmd.c */
+int RIOFoadRta(struct Host *, struct Map *);
+int RIOZombieRta(struct Host *, struct Map *);
+int RIOCommandRta(struct rio_info *, unsigned long, int (*func) (struct Host *, struct Map *));
+int RIOIdentifyRta(struct rio_info *, void __user *);
+int RIOKillNeighbour(struct rio_info *, void __user *);
+int RIOSuspendBootRta(struct Host *, int, int);
+int RIOFoadWakeup(struct rio_info *);
+struct CmdBlk *RIOGetCmdBlk(void);
+void RIOFreeCmdBlk(struct CmdBlk *);
+int RIOQueueCmdBlk(struct Host *, unsigned int, struct CmdBlk *);
+void RIOPollHostCommands(struct rio_info *, struct Host *);
+int RIOWFlushMark(unsigned long, struct CmdBlk *);
+int RIORFlushEnable(unsigned long, struct CmdBlk *);
+int RIOUnUse(unsigned long, struct CmdBlk *);
+
+/* rioctrl.c */
+int riocontrol(struct rio_info *, dev_t, int, unsigned long, int);
+
+int RIOPreemptiveCmd(struct rio_info *, struct Port *, unsigned char);
+
+/* rioinit.c */
+void rioinit(struct rio_info *, struct RioHostInfo *);
+void RIOInitHosts(struct rio_info *, struct RioHostInfo *);
+void RIOISAinit(struct rio_info *, int);
+int RIODoAT(struct rio_info *, int, int);
+caddr_t RIOCheckForATCard(int);
+int RIOAssignAT(struct rio_info *, int, void __iomem *, int);
+int RIOBoardTest(unsigned long, void __iomem *, unsigned char, int);
+void RIOAllocDataStructs(struct rio_info *);
+void RIOSetupDataStructs(struct rio_info *);
+int RIODefaultName(struct rio_info *, struct Host *, unsigned int);
+struct rioVersion *RIOVersid(void);
+void RIOHostReset(unsigned int, struct DpRam __iomem *, unsigned int);
+
+/* riointr.c */
+void RIOTxEnable(char *);
+void RIOServiceHost(struct rio_info *, struct Host *);
+int riotproc(struct rio_info *, struct ttystatics *, int, int);
+
+/* rioparam.c */
+int RIOParam(struct Port *, int, int, int);
+int RIODelay(struct Port *PortP, int);
+int RIODelay_ni(struct Port *PortP, int);
+void ms_timeout(struct Port *);
+int can_add_transmit(struct PKT __iomem **, struct Port *);
+void add_transmit(struct Port *);
+void put_free_end(struct Host *, struct PKT __iomem *);
+int can_remove_receive(struct PKT __iomem **, struct Port *);
+void remove_receive(struct Port *);
+
+/* rioroute.c */
+int RIORouteRup(struct rio_info *, unsigned int, struct Host *, struct PKT __iomem *);
+void RIOFixPhbs(struct rio_info *, struct Host *, unsigned int);
+unsigned int GetUnitType(unsigned int);
+int RIOSetChange(struct rio_info *);
+int RIOFindFreeID(struct rio_info *, struct Host *, unsigned int *, unsigned int *);
+
+
+/* riotty.c */
+
+int riotopen(struct tty_struct *tty, struct file *filp);
+int riotclose(void *ptr);
+int riotioctl(struct rio_info *, struct tty_struct *, int, caddr_t);
+void ttyseth(struct Port *, struct ttystatics *, struct old_sgttyb *sg);
+
+/* riotable.c */
+int RIONewTable(struct rio_info *);
+int RIOApel(struct rio_info *);
+int RIODeleteRta(struct rio_info *, struct Map *);
+int RIOAssignRta(struct rio_info *, struct Map *);
+int RIOReMapPorts(struct rio_info *, struct Host *, struct Map *);
+int RIOChangeName(struct rio_info *, struct Map *);
+
+#if 0
+/* riodrvr.c */
+struct rio_info *rio_install(struct RioHostInfo *);
+int rio_uninstall(struct rio_info *);
+int rio_open(struct rio_info *, int, struct file *);
+int rio_close(struct rio_info *, struct file *);
+int rio_read(struct rio_info *, struct file *, char *, int);
+int rio_write(struct rio_info *, struct file *f, char *, int);
+int rio_ioctl(struct rio_info *, struct file *, int, char *);
+int rio_select(struct rio_info *, struct file *f, int, struct sel *);
+int rio_intr(char *);
+int rio_isr_thread(char *);
+struct rio_info *rio_info_store(int cmd, struct rio_info *p);
+#endif
+
+extern void rio_copy_to_card(void *from, void __iomem *to, int len);
+extern int rio_minor(struct tty_struct *tty);
+extern int rio_ismodem(struct tty_struct *tty);
+
+extern void rio_start_card_running(struct Host *HostP);
+
+#endif				/* __func_h_def */
diff --git a/drivers/staging/generic_serial/rio/host.h b/drivers/staging/generic_serial/rio/host.h
new file mode 100644
index 0000000..78f2454
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/host.h
@@ -0,0 +1,123 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: host.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:10
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)host.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_host_h__
+#define __rio_host_h__
+
+/*
+** the host structure - one per host card in the system.
+*/
+
+#define	MAX_EXTRA_UNITS	64
+
+/*
+**    Host data structure. This is used for the software equiv. of
+**    the host.
+*/
+struct Host {
+	struct pci_dev *pdev;
+	unsigned char Type;		/* RIO_EISA, RIO_MCA, ... */
+	unsigned char Ivec;		/* POLLED or ivec number */
+	unsigned char Mode;		/* Control stuff */
+	unsigned char Slot;		/* Slot */
+	void  __iomem *Caddr;		/* KV address of DPRAM */
+	struct DpRam __iomem *CardP;	/* KV address of DPRAM, with overlay */
+	unsigned long PaddrP;		/* Phys. address of DPRAM */
+	char Name[MAX_NAME_LEN];	/* The name of the host */
+	unsigned int UniqueNum;		/* host unique number */
+	spinlock_t HostLock;	/* Lock structure for MPX */
+	unsigned int WorkToBeDone;	/* set to true each interrupt */
+	unsigned int InIntr;		/* Being serviced? */
+	unsigned int IntSrvDone;	/* host's interrupt has been serviced */
+	void (*Copy) (void *, void __iomem *, int);	/* copy func */
+	struct timer_list timer;
+	/*
+	 **               I M P O R T A N T !
+	 **
+	 ** The rest of this data structure is cleared to zero after
+	 ** a RIO_HOST_FOAD command.
+	 */
+
+	unsigned long Flags;			/* Whats going down */
+#define RC_WAITING            0
+#define RC_STARTUP            1
+#define RC_RUNNING            2
+#define RC_STUFFED            3
+#define RC_READY              7
+#define RUN_STATE             7
+/*
+** Boot mode applies to the way in which hosts in this system will
+** boot RTAs
+*/
+#define RC_BOOT_ALL           0x8		/* Boot all RTAs attached */
+#define RC_BOOT_OWN           0x10		/* Only boot RTAs bound to this system */
+#define RC_BOOT_NONE          0x20		/* Don't boot any RTAs (slave mode) */
+
+	struct Top Topology[LINKS_PER_UNIT];	/* one per link */
+	struct Map Mapping[MAX_RUP];		/* Mappings for host */
+	struct PHB __iomem *PhbP;		/* Pointer to the PHB array */
+	unsigned short __iomem *PhbNumP;	/* Ptr to Number of PHB's */
+	struct LPB __iomem *LinkStrP;		/* Link Structure Array */
+	struct RUP __iomem *RupP;		/* Sixteen real rups here */
+	struct PARM_MAP __iomem *ParmMapP;	/* points to the parmmap */
+	unsigned int ExtraUnits[MAX_EXTRA_UNITS];	/* unknown things */
+	unsigned int NumExtraBooted;		/* how many of the above */
+	/*
+	 ** Twenty logical rups.
+	 ** The first sixteen are the real Rup entries (above), the last four
+	 ** are the link RUPs.
+	 */
+	struct UnixRup UnixRups[MAX_RUP + LINKS_PER_UNIT];
+	int timeout_id;				/* For calling 100 ms delays */
+	int timeout_sem;			/* For calling 100 ms delays */
+	unsigned long locks;			/* long req'd for set_bit --RR */
+	char ____end_marker____;
+};
+#define Control      CardP->DpControl
+#define SetInt       CardP->DpSetInt
+#define ResetTpu     CardP->DpResetTpu
+#define ResetInt     CardP->DpResetInt
+#define Signature    CardP->DpSignature
+#define Sram1        CardP->DpSram1
+#define Sram2        CardP->DpSram2
+#define Sram3        CardP->DpSram3
+#define Scratch      CardP->DpScratch
+#define __ParmMapR   CardP->DpParmMapR
+#define SLX          CardP->DpSlx
+#define Revision     CardP->DpRevision
+#define Unique       CardP->DpUnique
+#define Year         CardP->DpYear
+#define Week         CardP->DpWeek
+
+#define RIO_DUMBPARM 0x0860	/* what not to expect */
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/link.h b/drivers/staging/generic_serial/rio/link.h
new file mode 100644
index 0000000..f3bf11a0
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/link.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                      L I N K
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _link_h
+#define _link_h 1
+
+/*************************************************
+ * Define the Link Status stuff
+ ************************************************/
+/* Boot request stuff */
+#define BOOT_REQUEST       ((ushort) 0)	/* Request for a boot */
+#define BOOT_ABORT         ((ushort) 1)	/* Abort a boot */
+#define BOOT_SEQUENCE      ((ushort) 2)	/* Packet with the number of packets
+					   and load address */
+#define BOOT_COMPLETED     ((ushort) 3)	/* Boot completed */
+
+
+struct LPB {
+	u16 link_number;	/* Link Number */
+	u16 in_ch;	/* Link In Channel */
+	u16 out_ch;	/* Link Out Channel */
+	u8 attached_serial[4];  /* Attached serial number */
+	u8 attached_host_serial[4];
+	/* Serial number of Host who
+	   booted the other end */
+	u16 descheduled;	/* Currently Descheduled */
+	u16 state;		/* Current state */
+	u16 send_poll;		/* Send a Poll Packet */
+	u16 ltt_p;	/* Process Descriptor */
+	u16 lrt_p;	/* Process Descriptor */
+	u16 lrt_status;		/* Current lrt status */
+	u16 ltt_status;		/* Current ltt status */
+	u16 timeout;		/* Timeout value */
+	u16 topology;		/* Topology bits */
+	u16 mon_ltt;
+	u16 mon_lrt;
+	u16 WaitNoBoot;	/* Secs to hold off booting */
+	u16 add_packet_list;	/* Add packets to here */
+	u16 remove_packet_list;	/* Send packets from here */
+
+	u16 lrt_fail_chan;	/* Lrt's failure channel */
+	u16 ltt_fail_chan;	/* Ltt's failure channel */
+
+	/* RUP structure for HOST to driver communications */
+	struct RUP rup;
+	struct RUP link_rup;	/* RUP for the link (POLL,
+				   topology etc.) */
+	u16 attached_link;	/* Number of attached link */
+	u16 csum_errors;	/* csum errors */
+	u16 num_disconnects;	/* number of disconnects */
+	u16 num_sync_rcvd;	/* # sync's received */
+	u16 num_sync_rqst;	/* # sync requests */
+	u16 num_tx;		/* Num pkts sent */
+	u16 num_rx;		/* Num pkts received */
+	u16 module_attached;	/* Module tpyes of attached */
+	u16 led_timeout;	/* LED timeout */
+	u16 first_port;		/* First port to service */
+	u16 last_port;		/* Last port to service */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/linux_compat.h b/drivers/staging/generic_serial/rio/linux_compat.h
new file mode 100644
index 0000000..34c0d28
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/linux_compat.h
@@ -0,0 +1,77 @@
+/*
+ * (C) 2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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 <linux/interrupt.h>
+
+
+#define DEBUG_ALL
+
+struct ttystatics {
+	struct termios tm;
+};
+
+extern int rio_debug;
+
+#define RIO_DEBUG_INIT         0x000001
+#define RIO_DEBUG_BOOT         0x000002
+#define RIO_DEBUG_CMD          0x000004
+#define RIO_DEBUG_CTRL         0x000008
+#define RIO_DEBUG_INTR         0x000010
+#define RIO_DEBUG_PARAM        0x000020
+#define RIO_DEBUG_ROUTE        0x000040
+#define RIO_DEBUG_TABLE        0x000080
+#define RIO_DEBUG_TTY          0x000100
+#define RIO_DEBUG_FLOW         0x000200
+#define RIO_DEBUG_MODEMSIGNALS 0x000400
+#define RIO_DEBUG_PROBE        0x000800
+#define RIO_DEBUG_CLEANUP      0x001000
+#define RIO_DEBUG_IFLOW        0x002000
+#define RIO_DEBUG_PFE          0x004000
+#define RIO_DEBUG_REC          0x008000
+#define RIO_DEBUG_SPINLOCK     0x010000
+#define RIO_DEBUG_DELAY        0x020000
+#define RIO_DEBUG_MOD_COUNT    0x040000
+
+
+/* Copied over from riowinif.h . This is ugly. The winif file declares
+also much other stuff which is incompatible with the headers from
+the older driver. The older driver includes "brates.h" which shadows
+the definitions from Linux, and is incompatible... */
+
+/* RxBaud and TxBaud definitions... */
+#define	RIO_B0			0x00	/* RTS / DTR signals dropped */
+#define	RIO_B50			0x01	/* 50 baud */
+#define	RIO_B75			0x02	/* 75 baud */
+#define	RIO_B110		0x03	/* 110 baud */
+#define	RIO_B134		0x04	/* 134.5 baud */
+#define	RIO_B150		0x05	/* 150 baud */
+#define	RIO_B200		0x06	/* 200 baud */
+#define	RIO_B300		0x07	/* 300 baud */
+#define	RIO_B600		0x08	/* 600 baud */
+#define	RIO_B1200		0x09	/* 1200 baud */
+#define	RIO_B1800		0x0A	/* 1800 baud */
+#define	RIO_B2400		0x0B	/* 2400 baud */
+#define	RIO_B4800		0x0C	/* 4800 baud */
+#define	RIO_B9600		0x0D	/* 9600 baud */
+#define	RIO_B19200		0x0E	/* 19200 baud */
+#define	RIO_B38400		0x0F	/* 38400 baud */
+#define	RIO_B56000		0x10	/* 56000 baud */
+#define	RIO_B57600		0x11	/* 57600 baud */
+#define	RIO_B64000		0x12	/* 64000 baud */
+#define	RIO_B115200		0x13	/* 115200 baud */
+#define	RIO_B2000		0x14	/* 2000 baud */
diff --git a/drivers/staging/generic_serial/rio/map.h b/drivers/staging/generic_serial/rio/map.h
new file mode 100644
index 0000000..8366978
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/map.h
@@ -0,0 +1,98 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: map.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:11
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)map.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_map_h__
+#define __rio_map_h__
+
+/*
+** mapping structure passed to and from the config.rio program to
+** determine the current topology of the world
+*/
+
+#define MAX_MAP_ENTRY 17
+#define	TOTAL_MAP_ENTRIES (MAX_MAP_ENTRY*RIO_SLOTS)
+#define	MAX_NAME_LEN 32
+
+struct Map {
+	unsigned int HostUniqueNum;	/* Supporting hosts unique number */
+	unsigned int RtaUniqueNum;	/* Unique number */
+	/*
+	 ** The next two IDs must be swapped on big-endian architectures
+	 ** when using a v2.04 /etc/rio/config with a v3.00 driver (when
+	 ** upgrading for example).
+	 */
+	unsigned short ID;		/* ID used in the subnet */
+	unsigned short ID2;		/* ID of 2nd block of 8 for 16 port */
+	unsigned long Flags;		/* Booted, ID Given, Disconnected */
+	unsigned long SysPort;		/* First tty mapped to this port */
+	struct Top Topology[LINKS_PER_UNIT];	/* ID connected to each link */
+	char Name[MAX_NAME_LEN];	/* Cute name by which RTA is known */
+};
+
+/*
+** Flag values:
+*/
+#define	RTA_BOOTED		0x00000001
+#define RTA_NEWBOOT		0x00000010
+#define	MSG_DONE		0x00000020
+#define	RTA_INTERCONNECT	0x00000040
+#define	RTA16_SECOND_SLOT	0x00000080
+#define	BEEN_HERE		0x00000100
+#define SLOT_TENTATIVE		0x40000000
+#define SLOT_IN_USE		0x80000000
+
+/*
+** HostUniqueNum is the unique number from the host card that this RTA
+** is to be connected to.
+** RtaUniqueNum is the unique number of the RTA concerned. It will be ZERO
+** if the slot in the table is unused. If it is the same as the HostUniqueNum
+** then this slot represents a host card.
+** Flags contains current boot/route state info
+** SysPort is a value in the range 0-504, being the number of the first tty
+** on this RTA. Each RTA supports 8 ports. The SysPort value must be modulo 8.
+** SysPort 0-127 correspond to /dev/ttyr001 to /dev/ttyr128, with minor
+** numbers 0-127. SysPort 128-255 correspond to /dev/ttyr129 to /dev/ttyr256,
+** again with minor numbers 0-127, and so on for SysPorts 256-383 and 384-511
+** ID will be in the range 0-16 for a `known' RTA. ID will be 0xFFFF for an
+** unused slot/unknown ID etc.
+** The Topology array contains the ID of the unit connected to each of the
+** four links on this unit. The entry will be 0xFFFF if NOTHING is connected
+** to the link, or will be 0xFF00 if an UNKNOWN unit is connected to the link.
+** The Name field is a null-terminated string, upto 31 characters, containing
+** the 'cute' name that the sysadmin/users know the RTA by. It is permissible
+** for this string to contain any character in the range \040 to \176 inclusive.
+** In particular, ctrl sequences and DEL (0x7F, \177) are not allowed. The
+** special character '%' IS allowable, and needs no special action.
+**
+*/
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/param.h b/drivers/staging/generic_serial/rio/param.h
new file mode 100644
index 0000000..7e9b628
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/param.h
@@ -0,0 +1,55 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: param.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)param.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_param_h__
+#define __rio_param_h__
+
+/*
+** the param command block, as used in OPEN and PARAM calls.
+*/
+
+struct phb_param {
+	u8 Cmd;			/* It is very important that these line up */
+	u8 Cor1;		/* with what is expected at the other end. */
+	u8 Cor2;		/* to confirm that you've got it right,    */
+	u8 Cor4;		/* check with cirrus/cirrus.h              */
+	u8 Cor5;
+	u8 TxXon;		/* Transmit X-On character */
+	u8 TxXoff;		/* Transmit X-Off character */
+	u8 RxXon;		/* Receive X-On character */
+	u8 RxXoff;		/* Receive X-Off character */
+	u8 LNext;		/* Literal-next character */
+	u8 TxBaud;		/* Transmit baudrate */
+	u8 RxBaud;		/* Receive baudrate */
+};
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/parmmap.h b/drivers/staging/generic_serial/rio/parmmap.h
new file mode 100644
index 0000000..acc8fa43
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/parmmap.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               H O S T   M E M O R Y  M A P
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+6/4/1991   jonb		     Made changes to accommodate Mips R3230 bus
+ ***************************************************************************/
+
+#ifndef _parmap_h
+#define _parmap_h
+
+typedef struct PARM_MAP PARM_MAP;
+
+struct PARM_MAP {
+	u16 phb_ptr;	/* Pointer to the PHB array */
+	u16 phb_num_ptr;	/* Ptr to Number of PHB's */
+	u16 free_list;	/* Free List pointer */
+	u16 free_list_end;	/* Free List End pointer */
+	u16 q_free_list_ptr;	/* Ptr to Q_BUF variable */
+	u16 unit_id_ptr;	/* Unit Id */
+	u16 link_str_ptr;	/* Link Structure Array */
+	u16 bootloader_1;	/* 1st Stage Boot Loader */
+	u16 bootloader_2;	/* 2nd Stage Boot Loader */
+	u16 port_route_map_ptr;	/* Port Route Map */
+	u16 route_ptr;		/* Unit Route Map */
+	u16 map_present;	/* Route Map present */
+	s16 pkt_num;		/* Total number of packets */
+	s16 q_num;		/* Total number of Q packets */
+	u16 buffers_per_port;	/* Number of buffers per port */
+	u16 heap_size;		/* Initial size of heap */
+	u16 heap_left;		/* Current Heap left */
+	u16 error;		/* Error code */
+	u16 tx_max;		/* Max number of tx pkts per phb */
+	u16 rx_max;		/* Max number of rx pkts per phb */
+	u16 rx_limit;		/* For high / low watermarks */
+	s16 links;		/* Links to use */
+	s16 timer;		/* Interrupts per second */
+	u16 rups;		/* Pointer to the RUPs */
+	u16 max_phb;		/* Mostly for debugging */
+	u16 living;		/* Just increments!! */
+	u16 init_done;		/* Initialisation over */
+	u16 booting_link;
+	u16 idle_count;		/* Idle time counter */
+	u16 busy_count;		/* Busy counter */
+	u16 idle_control;	/* Control Idle Process */
+	u16 tx_intr;		/* TX interrupt pending */
+	u16 rx_intr;		/* RX interrupt pending */
+	u16 rup_intr;		/* RUP interrupt pending */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/pci.h b/drivers/staging/generic_serial/rio/pci.h
new file mode 100644
index 0000000..6032f91
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/pci.h
@@ -0,0 +1,72 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: pci.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)pci.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_pci_h__
+#define	__rio_pci_h__
+
+/*
+** PCI stuff
+*/
+
+#define	PCITpFastClock		0x80
+#define	PCITpSlowClock		0x00
+#define	PCITpFastLinks	        0x40
+#define	PCITpSlowLinks	        0x00
+#define	PCITpIntEnable		0x04
+#define	PCITpIntDisable		0x00
+#define	PCITpBusEnable		0x02
+#define	PCITpBusDisable		0x00
+#define	PCITpBootFromRam	0x01
+#define	PCITpBootFromLink	0x00
+
+#define	RIO_PCI_VENDOR		0x11CB
+#define	RIO_PCI_DEVICE		0x8000
+#define	RIO_PCI_BASE_CLASS	0x02
+#define	RIO_PCI_SUB_CLASS	0x80
+#define	RIO_PCI_PROG_IFACE	0x00
+
+#define RIO_PCI_RID		0x0008
+#define RIO_PCI_BADR0		0x0010
+#define RIO_PCI_INTLN		0x003C
+#define RIO_PCI_INTPIN		0x003D
+
+#define	RIO_PCI_MEM_SIZE	65536
+
+#define	RIO_PCI_TURBO_TP	0x80
+#define	RIO_PCI_FAST_LINKS	0x40
+#define	RIO_PCI_INT_ENABLE	0x04
+#define	RIO_PCI_TP_BUS_ENABLE	0x02
+#define	RIO_PCI_BOOT_FROM_RAM	0x01
+
+#define	RIO_PCI_DEFAULT_MODE	0x05
+
+#endif				/* __rio_pci_h__ */
diff --git a/drivers/staging/generic_serial/rio/phb.h b/drivers/staging/generic_serial/rio/phb.h
new file mode 100644
index 0000000..a4c48ae
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/phb.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 P H B     H E A D E R                        *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra, Jeremy Rolls
+ Date    : 
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _phb_h
+#define _phb_h 1
+
+/*************************************************
+ * Handshake asserted. Deasserted by the LTT(s)
+ ************************************************/
+#define PHB_HANDSHAKE_SET      ((ushort) 0x001)	/* Set by LRT */
+
+#define PHB_HANDSHAKE_RESET     ((ushort) 0x002)	/* Set by ISR / driver */
+
+#define PHB_HANDSHAKE_FLAGS     (PHB_HANDSHAKE_RESET | PHB_HANDSHAKE_SET)
+						/* Reset by ltt */
+
+
+/*************************************************
+ * Maximum number of PHB's
+ ************************************************/
+#define MAX_PHB               ((ushort) 128)	/* range 0-127 */
+
+/*************************************************
+ * Defines for the mode fields
+ ************************************************/
+#define TXPKT_INCOMPLETE        0x0001	/* Previous tx packet not completed */
+#define TXINTR_ENABLED          0x0002	/* Tx interrupt is enabled */
+#define TX_TAB3                 0x0004	/* TAB3 mode */
+#define TX_OCRNL                0x0008	/* OCRNL mode */
+#define TX_ONLCR                0x0010	/* ONLCR mode */
+#define TX_SENDSPACES           0x0020	/* Send n spaces command needs
+					   completing */
+#define TX_SENDNULL             0x0040	/* Escaping NULL needs completing */
+#define TX_SENDLF               0x0080	/* LF -> CR LF needs completing */
+#define TX_PARALLELBUG          0x0100	/* CD1400 LF -> CR LF bug on parallel
+					   port */
+#define TX_HANGOVER             (TX_SENDSPACES | TX_SENDLF | TX_SENDNULL)
+#define TX_DTRFLOW		0x0200	/* DTR tx flow control */
+#define	TX_DTRFLOWED		0x0400	/* DTR is low - don't allow more data
+					   into the FIFO */
+#define	TX_DATAINFIFO		0x0800	/* There is data in the FIFO */
+#define	TX_BUSY			0x1000	/* Data in FIFO, shift or holding regs */
+
+#define RX_SPARE	        0x0001	/* SPARE */
+#define RXINTR_ENABLED          0x0002	/* Rx interrupt enabled */
+#define RX_ICRNL                0x0008	/* ICRNL mode */
+#define RX_INLCR                0x0010	/* INLCR mode */
+#define RX_IGNCR                0x0020	/* IGNCR mode */
+#define RX_CTSFLOW              0x0040	/* CTSFLOW enabled */
+#define RX_IXOFF                0x0080	/* IXOFF enabled */
+#define RX_CTSFLOWED            0x0100	/* CTSFLOW and CTS dropped */
+#define RX_IXOFFED              0x0200	/* IXOFF and xoff sent */
+#define RX_BUFFERED		0x0400	/* Try and pass on complete packets */
+
+#define PORT_ISOPEN             0x0001	/* Port open? */
+#define PORT_HUPCL              0x0002	/* Hangup on close? */
+#define PORT_MOPENPEND          0x0004	/* Modem open pending */
+#define PORT_ISPARALLEL         0x0008	/* Parallel port */
+#define PORT_BREAK              0x0010	/* Port on break */
+#define PORT_STATUSPEND		0x0020	/* Status packet pending */
+#define PORT_BREAKPEND          0x0040	/* Break packet pending */
+#define PORT_MODEMPEND          0x0080	/* Modem status packet pending */
+#define PORT_PARALLELBUG        0x0100	/* CD1400 LF -> CR LF bug on parallel
+					   port */
+#define PORT_FULLMODEM          0x0200	/* Full modem signals */
+#define PORT_RJ45               0x0400	/* RJ45 connector - no RI signal */
+#define PORT_RESTRICTED         0x0600	/* Restricted connector - no RI / DTR */
+
+#define PORT_MODEMBITS          0x0600	/* Mask for modem fields */
+
+#define PORT_WCLOSE             0x0800	/* Waiting for close */
+#define	PORT_HANDSHAKEFIX	0x1000	/* Port has H/W flow control fix */
+#define	PORT_WASPCLOSED		0x2000	/* Port closed with PCLOSE */
+#define	DUMPMODE		0x4000	/* Dump RTA mem */
+#define	READ_REG		0x8000	/* Read CD1400 register */
+
+
+
+/**************************************************************************
+ * PHB Structure
+ * A  few words.
+ *
+ * Normally Packets are added to the end of the list and removed from
+ * the start. The pointer tx_add points to a SPACE to put a Packet.
+ * The pointer tx_remove points to the next Packet to remove
+ *************************************************************************/
+
+struct PHB {
+	u8 source;
+	u8 handshake;
+	u8 status;
+	u16 timeout;		/* Maximum of 1.9 seconds */
+	u8 link;		/* Send down this link */
+	u8 destination;
+	u16 tx_start;
+	u16 tx_end;
+	u16 tx_add;
+	u16 tx_remove;
+
+	u16 rx_start;
+	u16 rx_end;
+	u16 rx_add;
+	u16 rx_remove;
+
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/pkt.h b/drivers/staging/generic_serial/rio/pkt.h
new file mode 100644
index 0000000..a945816
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/pkt.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+ *******                                                              *******
+ *******            P A C K E T   H E A D E R   F I L E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _pkt_h
+#define _pkt_h 1
+
+#define PKT_CMD_BIT     ((ushort) 0x080)
+#define PKT_CMD_DATA    ((ushort) 0x080)
+
+#define PKT_ACK         ((ushort) 0x040)
+
+#define PKT_TGL         ((ushort) 0x020)
+
+#define PKT_LEN_MASK    ((ushort) 0x07f)
+
+#define DATA_WNDW       ((ushort) 0x10)
+#define PKT_TTL_MASK    ((ushort) 0x0f)
+
+#define PKT_MAX_DATA_LEN   72
+
+#define PKT_LENGTH         sizeof(struct PKT)
+#define SYNC_PKT_LENGTH    (PKT_LENGTH + 4)
+
+#define CONTROL_PKT_LEN_MASK PKT_LEN_MASK
+#define CONTROL_PKT_CMD_BIT  PKT_CMD_BIT
+#define CONTROL_PKT_ACK (PKT_ACK << 8)
+#define CONTROL_PKT_TGL (PKT_TGL << 8)
+#define CONTROL_PKT_TTL_MASK (PKT_TTL_MASK << 8)
+#define CONTROL_DATA_WNDW  (DATA_WNDW << 8)
+
+struct PKT {
+	u8 dest_unit;		/* Destination Unit Id */
+	u8 dest_port;		/* Destination POrt */
+	u8 src_unit;		/* Source Unit Id */
+	u8 src_port;		/* Source POrt */
+	u8 len;
+	u8 control;
+	u8 data[PKT_MAX_DATA_LEN];
+	/* Actual data :-) */
+	u16 csum;		/* C-SUM */
+};
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/port.h b/drivers/staging/generic_serial/rio/port.h
new file mode 100644
index 0000000..49cf6d1
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/port.h
@@ -0,0 +1,179 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: port.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:12
+**	Retrieved	: 11/6/98 11:34:21
+**
+**  ident @(#)port.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_port_h__
+#define	__rio_port_h__
+
+/*
+**	Port data structure
+*/
+struct Port {
+	struct gs_port gs;
+	int PortNum;			/* RIO port no., 0-511 */
+	struct Host *HostP;
+	void __iomem *Caddr;
+	unsigned short HostPort;	/* Port number on host card */
+	unsigned char RupNum;		/* Number of RUP for port */
+	unsigned char ID2;		/* Second ID of RTA for port */
+	unsigned long State;		/* FLAGS for open & xopen */
+#define	RIO_LOPEN	0x00001		/* Local open */
+#define	RIO_MOPEN	0x00002		/* Modem open */
+#define	RIO_WOPEN	0x00004		/* Waiting for open */
+#define	RIO_CLOSING	0x00008		/* The port is being close */
+#define	RIO_XPBUSY	0x00010		/* Transparent printer busy */
+#define	RIO_BREAKING	0x00020		/* Break in progress */
+#define	RIO_DIRECT	0x00040		/* Doing Direct output */
+#define	RIO_EXCLUSIVE	0x00080		/* Stream open for exclusive use */
+#define	RIO_NDELAY	0x00100		/* Stream is open FNDELAY */
+#define	RIO_CARR_ON	0x00200		/* Stream has carrier present */
+#define	RIO_XPWANTR	0x00400		/* Stream wanted by Xprint */
+#define	RIO_RBLK	0x00800		/* Stream is read-blocked */
+#define	RIO_BUSY	0x01000		/* Stream is BUSY for write */
+#define	RIO_TIMEOUT	0x02000		/* Stream timeout in progress */
+#define	RIO_TXSTOP	0x04000		/* Stream output is stopped */
+#define	RIO_WAITFLUSH	0x08000		/* Stream waiting for flush */
+#define	RIO_DYNOROD	0x10000		/* Drain failed */
+#define	RIO_DELETED	0x20000		/* RTA has been deleted */
+#define RIO_ISSCANCODE	0x40000		/* This line is in scancode mode */
+#define	RIO_USING_EUC	0x100000	/* Using extended Unix chars */
+#define	RIO_CAN_COOK	0x200000	/* This line can do cooking */
+#define RIO_TRIAD_MODE  0x400000	/* Enable TRIAD special ops. */
+#define RIO_TRIAD_BLOCK 0x800000	/* Next read will block */
+#define RIO_TRIAD_FUNC  0x1000000	/* Seen a function key coming in */
+#define RIO_THROTTLE_RX 0x2000000	/* RX needs to be throttled. */
+
+	unsigned long Config;		/* FLAGS for NOREAD.... */
+#define	RIO_NOREAD	0x0001		/* Are not allowed to read port */
+#define	RIO_NOWRITE	0x0002		/* Are not allowed to write port */
+#define	RIO_NOXPRINT	0x0004		/* Are not allowed to xprint port */
+#define	RIO_NOMASK	0x0007		/* All not allowed things */
+#define RIO_IXANY	0x0008		/* Port is allowed ixany */
+#define	RIO_MODEM	0x0010		/* Stream is a modem device */
+#define	RIO_IXON	0x0020		/* Port is allowed ixon */
+#define RIO_WAITDRAIN	0x0040		/* Wait for port to completely drain */
+#define RIO_MAP_50_TO_50	0x0080	/* Map 50 baud to 50 baud */
+#define RIO_MAP_110_TO_110	0x0100	/* Map 110 baud to 110 baud */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 prt fix
+** As LynxOS does not appear to support Hardware Flow Control .....
+** Define our own flow control flags in 'Config'.
+*/
+#define RIO_CTSFLOW	0x0200		/* RIO's own CTSFLOW flag */
+#define RIO_RTSFLOW	0x0400		/* RIO's own RTSFLOW flag */
+
+
+	struct PHB __iomem *PhbP;	/* pointer to PHB for port */
+	u16 __iomem *TxAdd;		/* Add packets here */
+	u16 __iomem *TxStart;		/* Start of add array */
+	u16 __iomem *TxEnd;		/* End of add array */
+	u16 __iomem *RxRemove;		/* Remove packets here */
+	u16 __iomem *RxStart;		/* Start of remove array */
+	u16 __iomem *RxEnd;		/* End of remove array */
+	unsigned int RtaUniqueNum;	/* Unique number of RTA */
+	unsigned short PortState;	/* status of port */
+	unsigned short ModemState;	/* status of modem lines */
+	unsigned long ModemLines;	/* Modem bits sent to RTA */
+	unsigned char CookMode;		/* who expands CR/LF? */
+	unsigned char ParamSem;		/* Prevent write during param */
+	unsigned char Mapped;		/* if port mapped onto host */
+	unsigned char SecondBlock;	/* if port belongs to 2nd block
+				   		of 16 port RTA */
+	unsigned char InUse;		/* how many pre-emptive cmds */
+	unsigned char Lock;		/* if params locked */
+	unsigned char Store;		/* if params stored across closes */
+	unsigned char FirstOpen;	/* TRUE if first time port opened */
+	unsigned char FlushCmdBodge;	/* if doing a (non)flush */
+	unsigned char MagicFlags;	/* require intr processing */
+#define	MAGIC_FLUSH	0x01		/* mirror of WflushFlag */
+#define	MAGIC_REBOOT	0x02		/* RTA re-booted, re-open ports */
+#define	MORE_OUTPUT_EYGOR 0x04		/* riotproc failed to empty clists */
+	unsigned char WflushFlag;	/* 1 How many WFLUSHs active */
+/*
+** Transparent print stuff
+*/
+	struct Xprint {
+#ifndef MAX_XP_CTRL_LEN
+#define MAX_XP_CTRL_LEN		16	/* ALSO IN DAEMON.H */
+#endif
+		unsigned int XpCps;
+		char XpOn[MAX_XP_CTRL_LEN];
+		char XpOff[MAX_XP_CTRL_LEN];
+		unsigned short XpLen;	/* strlen(XpOn)+strlen(XpOff) */
+		unsigned char XpActive;
+		unsigned char XpLastTickOk;	/* TRUE if we can process */
+#define	XP_OPEN		00001
+#define	XP_RUNABLE	00002
+		struct ttystatics *XttyP;
+	} Xprint;
+	unsigned char RxDataStart;
+	unsigned char Cor2Copy;		/* copy of COR2 */
+	char *Name;			/* points to the Rta's name */
+	char *TxRingBuffer;
+	unsigned short TxBufferIn;	/* New data arrives here */
+	unsigned short TxBufferOut;	/* Intr removes data here */
+	unsigned short OldTxBufferOut;	/* Indicates if draining */
+	int TimeoutId;			/* Timeout ID */
+	unsigned int Debug;
+	unsigned char WaitUntilBooted;	/* True if open should block */
+	unsigned int statsGather;	/* True if gathering stats */
+	unsigned long txchars;		/* Chars transmitted */
+	unsigned long rxchars;		/* Chars received */
+	unsigned long opens;		/* port open count */
+	unsigned long closes;		/* port close count */
+	unsigned long ioctls;		/* ioctl count */
+	unsigned char LastRxTgl;	/* Last state of rx toggle bit */
+	spinlock_t portSem;		/* Lock using this sem */
+	int MonitorTstate;		/* Monitoring ? */
+	int timeout_id;			/* For calling 100 ms delays */
+	int timeout_sem;		/* For calling 100 ms delays */
+	int firstOpen;			/* First time open ? */
+	char *p;			/* save the global struc here .. */
+};
+
+struct ModuleInfo {
+	char *Name;
+	unsigned int Flags[4];		/* one per port on a module */
+};
+
+/*
+** This struct is required because trying to grab an entire Port structure
+** runs into problems with differing struct sizes between driver and config.
+*/
+struct PortParams {
+	unsigned int Port;
+	unsigned long Config;
+	unsigned long State;
+	struct ttystatics *TtyP;
+};
+
+#endif
diff --git a/drivers/staging/generic_serial/rio/protsts.h b/drivers/staging/generic_serial/rio/protsts.h
new file mode 100644
index 0000000..8ab7940
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/protsts.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+ *******                                                              *******
+ *******      P R O T O C O L    S T A T U S   S T R U C T U R E      *******
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _protsts_h
+#define _protsts_h 1
+
+/*************************************************
+ * ACK bit. Last Packet received OK. Set by
+ * rxpkt to indicate that the Packet has been
+ * received OK and that the LTT must set the ACK
+ * bit in the next outward bound Packet
+ * and re-set by LTT's after xmit.
+ *
+ * Gets shoved into rx_status
+ ************************************************/
+#define PHB_RX_LAST_PKT_ACKED    ((ushort) 0x080)
+
+/*******************************************************
+ * The Rx TOGGLE bit.
+ * Stuffed into rx_status by RXPKT
+ ******************************************************/
+#define PHB_RX_DATA_WNDW         ((ushort) 0x040)
+
+/*******************************************************
+ * The Rx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into rx_status
+ ******************************************************/
+#define PHB_RX_TGL               ((ushort) 0x2000)
+
+
+/*************************************************
+ * This bit is set by the LRT to indicate that
+ * an ACK (packet) must be returned.
+ *
+ * Gets shoved into tx_status
+ ************************************************/
+#define PHB_TX_SEND_PKT_ACK      ((ushort) 0x08)
+
+/*************************************************
+ * Set by LTT to indicate that an ACK is required
+ *************************************************/
+#define PHB_TX_ACK_RQRD         ((ushort) 0x01)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit.
+ * Stuffed into tx_status by RXPKT from the PKT WndW
+ * field. Looked by the LTT when the NEXT Packet
+ * is going to be sent.
+ ******************************************************/
+#define PHB_TX_DATA_WNDW         ((ushort) 0x04)
+
+
+/*******************************************************
+ * The Tx TOGGLE bit. Matches the setting in PKT.H
+ * Stuffed into tx_status
+ ******************************************************/
+#define PHB_TX_TGL               ((ushort) 0x02)
+
+/*******************************************************
+ * Request intr bit. Set when the queue has gone quiet
+ * and the PHB has requested an interrupt.
+ ******************************************************/
+#define PHB_TX_INTR             ((ushort) 0x100)
+
+/*******************************************************
+ * SET if the PHB cannot send any more data down the
+ * Link
+ ******************************************************/
+#define PHB_TX_HANDSHAKE         ((ushort) 0x010)
+
+
+#define RUP_SEND_WNDW		 ((ushort) 0x08) ;
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/rio.h b/drivers/staging/generic_serial/rio/rio.h
new file mode 100644
index 0000000..1bf3622
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rio.h
@@ -0,0 +1,208 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 1998 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rio.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rio.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rio_rio_h__
+#define	__rio_rio_h__
+
+/*
+**	Maximum numbers of things
+*/
+#define	RIO_SLOTS	4	/* number of configuration slots */
+#define	RIO_HOSTS	4	/* number of hosts that can be found */
+#define	PORTS_PER_HOST	128	/* number of ports per host */
+#define	LINKS_PER_UNIT	4	/* number of links from a host */
+#define	RIO_PORTS	(PORTS_PER_HOST * RIO_HOSTS)	/* max. no. of ports */
+#define	RTAS_PER_HOST	(MAX_RUP)	/* number of RTAs per host */
+#define	PORTS_PER_RTA	(PORTS_PER_HOST/RTAS_PER_HOST)	/* ports on a rta */
+#define	PORTS_PER_MODULE 4	/* number of ports on a plug-in module */
+				/* number of modules on an RTA */
+#define	MODULES_PER_RTA	 (PORTS_PER_RTA/PORTS_PER_MODULE)
+#define MAX_PRODUCT	16	/* numbr of different product codes */
+#define MAX_MODULE_TYPES 16	/* number of different types of module */
+
+#define RIO_CONTROL_DEV	128	/* minor number of host/control device */
+#define RIO_INVALID_MAJOR 0	/* test first host card's major no for validity */
+
+/*
+** number of RTAs that can be bound to a master
+*/
+#define MAX_RTA_BINDINGS (MAX_RUP * RIO_HOSTS)
+
+/*
+**	Unit types
+*/
+#define PC_RTA16	0x90000000
+#define PC_RTA8		0xe0000000
+#define TYPE_HOST	0
+#define TYPE_RTA8	1
+#define TYPE_RTA16	2
+
+/*
+**	Flag values returned by functions
+*/
+
+#define	RIO_FAIL	-1
+
+/*
+** SysPort value for something that hasn't any ports
+*/
+#define	NO_PORT	0xFFFFFFFF
+
+/*
+** Unit ID Of all hosts
+*/
+#define	HOST_ID	0
+
+/*
+** Break bytes into nybles
+*/
+#define	LONYBLE(X)	((X) & 0xF)
+#define	HINYBLE(X)	(((X)>>4) & 0xF)
+
+/*
+** Flag values passed into some functions
+*/
+#define	DONT_SLEEP	0
+#define	OK_TO_SLEEP	1
+
+#define	DONT_PRINT	1
+#define	DO_PRINT	0
+
+#define PRINT_TO_LOG_CONS	0
+#define PRINT_TO_CONS	1
+#define PRINT_TO_LOG	2
+
+/*
+** Timeout has trouble with times of less than 3 ticks...
+*/
+#define	MIN_TIMEOUT	3
+
+/*
+**	Generally useful constants
+*/
+
+#define	HUNDRED_MS		((HZ/10)?(HZ/10):1)
+#define	ONE_MEG			0x100000
+#define	SIXTY_FOUR_K		0x10000
+
+#define	RIO_AT_MEM_SIZE		SIXTY_FOUR_K
+#define	RIO_EISA_MEM_SIZE	SIXTY_FOUR_K
+#define	RIO_MCA_MEM_SIZE	SIXTY_FOUR_K
+
+#define	COOK_WELL		0
+#define	COOK_MEDIUM		1
+#define	COOK_RAW		2
+
+/*
+**	Pointer manipulation stuff
+**	RIO_PTR takes hostp->Caddr and the offset into the DP RAM area
+**	and produces a UNIX caddr_t (pointer) to the object
+**	RIO_OBJ takes hostp->Caddr and a UNIX pointer to an object and
+**	returns the offset into the DP RAM area.
+*/
+#define	RIO_PTR(C,O) (((unsigned char __iomem *)(C))+(0xFFFF&(O)))
+#define	RIO_OFF(C,O) ((unsigned char __iomem *)(O)-(unsigned char __iomem *)(C))
+
+/*
+**	How to convert from various different device number formats:
+**	DEV is a dev number, as passed to open, close etc - NOT a minor
+**	number!
+**/
+
+#define	RIO_MODEM_MASK		0x1FF
+#define	RIO_MODEM_BIT		0x200
+#define	RIO_UNMODEM(DEV)	(MINOR(DEV) & RIO_MODEM_MASK)
+#define	RIO_ISMODEM(DEV)	(MINOR(DEV) & RIO_MODEM_BIT)
+#define RIO_PORT(DEV,FIRST_MAJ)	( (MAJOR(DEV) - FIRST_MAJ) * PORTS_PER_HOST) \
+					+ MINOR(DEV)
+#define CSUM(pkt_ptr)  (((u16 *)(pkt_ptr))[0] + ((u16 *)(pkt_ptr))[1] + \
+			((u16 *)(pkt_ptr))[2] + ((u16 *)(pkt_ptr))[3] + \
+			((u16 *)(pkt_ptr))[4] + ((u16 *)(pkt_ptr))[5] + \
+			((u16 *)(pkt_ptr))[6] + ((u16 *)(pkt_ptr))[7] + \
+			((u16 *)(pkt_ptr))[8] + ((u16 *)(pkt_ptr))[9] )
+
+#define	RIO_LINK_ENABLE	0x80FF	/* FF is a hack, mainly for Mips, to        */
+			       /* prevent a really stupid race condition.  */
+
+#define	NOT_INITIALISED	0
+#define	INITIALISED	1
+
+#define	NOT_POLLING	0
+#define	POLLING		1
+
+#define	NOT_CHANGED	0
+#define	CHANGED		1
+
+#define	NOT_INUSE	0
+
+#define	DISCONNECT	0
+#define	CONNECT		1
+
+/* ------ Control Codes ------ */
+
+#define	CONTROL		'^'
+#define IFOAD		( CONTROL + 1 )
+#define	IDENTIFY	( CONTROL + 2 )
+#define	ZOMBIE		( CONTROL + 3 )
+#define	UFOAD		( CONTROL + 4 )
+#define IWAIT		( CONTROL + 5 )
+
+#define	IFOAD_MAGIC	0xF0AD	/* of course */
+#define	ZOMBIE_MAGIC	(~0xDEAD)	/* not dead -> zombie */
+#define	UFOAD_MAGIC	0xD1E	/* kill-your-neighbour */
+#define	IWAIT_MAGIC	0xB1DE	/* Bide your time */
+
+/* ------ Error Codes ------ */
+
+#define E_NO_ERROR                       ((ushort) 0)
+
+/* ------ Free Lists ------ */
+
+struct rio_free_list {
+	u16 next;
+	u16 prev;
+};
+
+/* NULL for card side linked lists */
+#define	TPNULL	((ushort)(0x8000))
+/* We can add another packet to a transmit queue if the packet pointer pointed
+ * to by the TxAdd pointer has PKT_IN_USE clear in its address. */
+#define PKT_IN_USE    0x1
+
+/* ------ Topology ------ */
+
+struct Top {
+	u8 Unit;
+	u8 Link;
+};
+
+#endif				/* __rio_h__ */
diff --git a/drivers/staging/generic_serial/rio/rio_linux.c b/drivers/staging/generic_serial/rio/rio_linux.c
new file mode 100644
index 0000000..5e33293
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rio_linux.c
@@ -0,0 +1,1204 @@
+
+/* rio_linux.c -- Linux driver for the Specialix RIO series cards. 
+ *
+ *
+ *   (C) 1999 R.E.Wolff@BitWizard.nl
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (rio.txt) first.
+ *
+ *
+ *
+ *      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 <linux/module.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+
+#include <linux/generic_serial.h>
+#include <asm/uaccess.h>
+
+#include "linux_compat.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "protsts.h"
+#include "rioboard.h"
+
+
+#include "rio_linux.h"
+
+/* I don't think that this driver can handle more than 512 ports on
+one machine.  Specialix specifies max 4 boards in one machine. I don't
+know why. If you want to try anyway you'll have to increase the number
+of boards in rio.h.  You'll have to allocate more majors if you need
+more than 512 ports.... */
+
+#ifndef RIO_NORMAL_MAJOR0
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define RIO_NORMAL_MAJOR0  154
+#define RIO_NORMAL_MAJOR1  156
+#endif
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+#ifndef RIO_WINDOW_LEN
+#define RIO_WINDOW_LEN 0x10000
+#endif
+
+
+/* Configurable options: 
+   (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef RIO_PARANOIA_CHECK
+
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 1000
+   Hz, but it is user configurable. I don't recommend going above 1000
+   Hz. The interrupt ratelimit might trigger if the interrupt is
+   shared with a very active other device. 
+   undef this if you want to disable the check....
+*/
+#define IRQ_RATE_LIMIT 200
+
+
+/* These constants are derived from SCO Source */
+static DEFINE_MUTEX(rio_fw_mutex);
+static struct Conf
+ RIOConf = {
+	/* locator */ "RIO Config here",
+					/* startuptime */ HZ * 2,
+					/* how long to wait for card to run */
+				/* slowcook */ 0,
+				/* TRUE -> always use line disc. */
+				/* intrpolltime */ 1,
+				/* The frequency of OUR polls */
+				/* breakinterval */ 25,
+				/* x10 mS XXX: units seem to be 1ms not 10! -- REW */
+				/* timer */ 10,
+				/* mS */
+	/* RtaLoadBase */ 0x7000,
+	/* HostLoadBase */ 0x7C00,
+				/* XpHz */ 5,
+				/* number of Xprint hits per second */
+				/* XpCps */ 120,
+				/* Xprint characters per second */
+				/* XpOn */ "\033d#",
+				/* start Xprint for a wyse 60 */
+				/* XpOff */ "\024",
+				/* end Xprint for a wyse 60 */
+				/* MaxXpCps */ 2000,
+				/* highest Xprint speed */
+				/* MinXpCps */ 10,
+				/* slowest Xprint speed */
+				/* SpinCmds */ 1,
+				/* non-zero for mega fast boots */
+					/* First Addr */ 0x0A0000,
+					/* First address to look at */
+					/* Last Addr */ 0xFF0000,
+					/* Last address looked at */
+				/* BufferSize */ 1024,
+				/* Bytes per port of buffering */
+				/* LowWater */ 256,
+				/* how much data left before wakeup */
+				/* LineLength */ 80,
+				/* how wide is the console? */
+				/* CmdTimeout */ HZ,
+				/* how long a close command may take */
+};
+
+
+
+
+/* Function prototypes */
+
+static void rio_disable_tx_interrupts(void *ptr);
+static void rio_enable_tx_interrupts(void *ptr);
+static void rio_disable_rx_interrupts(void *ptr);
+static void rio_enable_rx_interrupts(void *ptr);
+static int rio_carrier_raised(struct tty_port *port);
+static void rio_shutdown_port(void *ptr);
+static int rio_set_real_termios(void *ptr);
+static void rio_hungup(void *ptr);
+static void rio_close(void *ptr);
+static int rio_chars_in_buffer(void *ptr);
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
+static int rio_init_drivers(void);
+
+static void my_hd(void *addr, int len);
+
+static struct tty_driver *rio_driver, *rio_driver2;
+
+/* The name "p" is a bit non-descript. But that's what the rio-lynxos
+sources use all over the place. */
+struct rio_info *p;
+
+int rio_debug;
+
+
+/* You can have the driver poll your card. 
+    - Set rio_poll to 1 to poll every timer tick (10ms on Intel). 
+      This is used when the card cannot use an interrupt for some reason.
+*/
+static int rio_poll = 1;
+
+
+/* These are the only open spaces in my computer. Yours may have more
+   or less.... */
+static int rio_probe_addrs[] = { 0xc0000, 0xd0000, 0xe0000 };
+
+#define NR_RIO_ADDRS ARRAY_SIZE(rio_probe_addrs)
+
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts. 
+   Some architectures may need more. -- Changed to LONG to
+   support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
+static long rio_irqmask = -1;
+
+MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
+MODULE_DESCRIPTION("RIO driver");
+MODULE_LICENSE("GPL");
+module_param(rio_poll, int, 0);
+module_param(rio_debug, int, 0644);
+module_param(rio_irqmask, long, 0);
+
+static struct real_driver rio_real_driver = {
+	rio_disable_tx_interrupts,
+	rio_enable_tx_interrupts,
+	rio_disable_rx_interrupts,
+	rio_enable_rx_interrupts,
+	rio_shutdown_port,
+	rio_set_real_termios,
+	rio_chars_in_buffer,
+	rio_close,
+	rio_hungup,
+	NULL
+};
+
+/* 
+ *  Firmware loader driver specific routines
+ *
+ */
+
+static const struct file_operations rio_fw_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = rio_fw_ioctl,
+	.llseek = noop_llseek,
+};
+
+static struct miscdevice rio_fw_device = {
+	RIOCTL_MISC_MINOR, "rioctl", &rio_fw_fops
+};
+
+
+
+
+
+#ifdef RIO_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int rio_paranoia_check(struct rio_port const *port, char *name, const char *routine)
+{
+
+	static const char *badmagic = KERN_ERR "rio: Warning: bad rio port magic number for device %s in %s\n";
+	static const char *badinfo = KERN_ERR "rio: Warning: null rio port for device %s in %s\n";
+
+	if (!port) {
+		printk(badinfo, name, routine);
+		return 1;
+	}
+	if (port->magic != RIO_MAGIC) {
+		printk(badmagic, name, routine);
+		return 1;
+	}
+
+	return 0;
+}
+#else
+#define rio_paranoia_check(a,b,c) 0
+#endif
+
+
+#ifdef DEBUG
+static void my_hd(void *ad, int len)
+{
+	int i, j, ch;
+	unsigned char *addr = ad;
+
+	for (i = 0; i < len; i += 16) {
+		rio_dprintk(RIO_DEBUG_PARAM, "%08lx ", (unsigned long) addr + i);
+		for (j = 0; j < 16; j++) {
+			rio_dprintk(RIO_DEBUG_PARAM, "%02x %s", addr[j + i], (j == 7) ? " " : "");
+		}
+		for (j = 0; j < 16; j++) {
+			ch = addr[j + i];
+			rio_dprintk(RIO_DEBUG_PARAM, "%c", (ch < 0x20) ? '.' : ((ch > 0x7f) ? '.' : ch));
+		}
+		rio_dprintk(RIO_DEBUG_PARAM, "\n");
+	}
+}
+#else
+#define my_hd(ad,len) do{/* nothing*/ } while (0)
+#endif
+
+
+/* Delay a number of jiffies, allowing a signal to interrupt */
+int RIODelay(struct Port *PortP, int njiffies)
+{
+	func_enter();
+
+	rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);
+	msleep_interruptible(jiffies_to_msecs(njiffies));
+	func_exit();
+
+	if (signal_pending(current))
+		return RIO_FAIL;
+	else
+		return !RIO_FAIL;
+}
+
+
+/* Delay a number of jiffies, disallowing a signal to interrupt */
+int RIODelay_ni(struct Port *PortP, int njiffies)
+{
+	func_enter();
+
+	rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);
+	msleep(jiffies_to_msecs(njiffies));
+	func_exit();
+	return !RIO_FAIL;
+}
+
+void rio_copy_to_card(void *from, void __iomem *to, int len)
+{
+	rio_copy_toio(to, from, len);
+}
+
+int rio_minor(struct tty_struct *tty)
+{
+	return tty->index + ((tty->driver == rio_driver) ? 0 : 256);
+}
+
+static int rio_set_real_termios(void *ptr)
+{
+	return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
+}
+
+
+static void rio_reset_interrupt(struct Host *HostP)
+{
+	func_enter();
+
+	switch (HostP->Type) {
+	case RIO_AT:
+	case RIO_MCA:
+	case RIO_PCI:
+		writeb(0xFF, &HostP->ResetInt);
+	}
+
+	func_exit();
+}
+
+
+static irqreturn_t rio_interrupt(int irq, void *ptr)
+{
+	struct Host *HostP;
+	func_enter();
+
+	HostP = ptr;			/* &p->RIOHosts[(long)ptr]; */
+	rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
+
+	/* AAargh! The order in which to do these things is essential and
+	   not trivial.
+
+	   - hardware twiddling goes before "recursive". Otherwise when we
+	   poll the card, and a recursive interrupt happens, we won't
+	   ack the card, so it might keep on interrupting us. (especially
+	   level sensitive interrupt systems like PCI).
+
+	   - Rate limit goes before hardware twiddling. Otherwise we won't
+	   catch a card that has gone bonkers.
+
+	   - The "initialized" test goes after the hardware twiddling. Otherwise
+	   the card will stick us in the interrupt routine again.
+
+	   - The initialized test goes before recursive.
+	 */
+
+	rio_dprintk(RIO_DEBUG_IFLOW, "rio: We've have noticed the interrupt\n");
+	if (HostP->Ivec == irq) {
+		/* Tell the card we've noticed the interrupt. */
+		rio_reset_interrupt(HostP);
+	}
+
+	if ((HostP->Flags & RUN_STATE) != RC_RUNNING)
+		return IRQ_HANDLED;
+
+	if (test_and_set_bit(RIO_BOARD_INTR_LOCK, &HostP->locks)) {
+		printk(KERN_ERR "Recursive interrupt! (host %p/irq%d)\n", ptr, HostP->Ivec);
+		return IRQ_HANDLED;
+	}
+
+	RIOServiceHost(p, HostP);
+
+	rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type);
+
+	clear_bit(RIO_BOARD_INTR_LOCK, &HostP->locks);
+	rio_dprintk(RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
+	func_exit();
+	return IRQ_HANDLED;
+}
+
+
+static void rio_pollfunc(unsigned long data)
+{
+	func_enter();
+
+	rio_interrupt(0, &p->RIOHosts[data]);
+	mod_timer(&p->RIOHosts[data].timer, jiffies + rio_poll);
+
+	func_exit();
+}
+
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the Specialix 
+   cards. ....   Hmm. Ok I figured it out. You don't.  -- REW */
+
+static void rio_disable_tx_interrupts(void *ptr)
+{
+	func_enter();
+
+	/*  port->gs.port.flags &= ~GS_TX_INTEN; */
+
+	func_exit();
+}
+
+
+static void rio_enable_tx_interrupts(void *ptr)
+{
+	struct Port *PortP = ptr;
+	/* int hn; */
+
+	func_enter();
+
+	/* hn = PortP->HostP - p->RIOHosts;
+
+	   rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn);
+	   rio_interrupt (-1,(void *) hn, NULL); */
+
+	RIOTxEnable((char *) PortP);
+
+	/*
+	 * In general we cannot count on "tx empty" interrupts, although
+	 * the interrupt routine seems to be able to tell the difference.
+	 */
+	PortP->gs.port.flags &= ~GS_TX_INTEN;
+
+	func_exit();
+}
+
+
+static void rio_disable_rx_interrupts(void *ptr)
+{
+	func_enter();
+	func_exit();
+}
+
+static void rio_enable_rx_interrupts(void *ptr)
+{
+	/*  struct rio_port *port = ptr; */
+	func_enter();
+	func_exit();
+}
+
+
+/* Jeez. Isn't this simple?  */
+static int rio_carrier_raised(struct tty_port *port)
+{
+	struct Port *PortP = container_of(port, struct Port, gs.port);
+	int rv;
+
+	func_enter();
+	rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
+
+	rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
+
+	func_exit();
+	return rv;
+}
+
+
+/* Jeez. Isn't this simple? Actually, we can sync with the actual port
+   by just pushing stuff into the queue going to the port... */
+static int rio_chars_in_buffer(void *ptr)
+{
+	func_enter();
+
+	func_exit();
+	return 0;
+}
+
+
+/* Nothing special here... */
+static void rio_shutdown_port(void *ptr)
+{
+	struct Port *PortP;
+
+	func_enter();
+
+	PortP = (struct Port *) ptr;
+	PortP->gs.port.tty = NULL;
+	func_exit();
+}
+
+
+/* I haven't the foggiest why the decrement use count has to happen
+   here. The whole linux serial drivers stuff needs to be redesigned.
+   My guess is that this is a hack to minimize the impact of a bug
+   elsewhere. Thinking about it some more. (try it sometime) Try
+   running minicom on a serial port that is driven by a modularized
+   driver. Have the modem hangup. Then remove the driver module. Then
+   exit minicom.  I expect an "oops".  -- REW */
+static void rio_hungup(void *ptr)
+{
+	struct Port *PortP;
+
+	func_enter();
+
+	PortP = (struct Port *) ptr;
+	PortP->gs.port.tty = NULL;
+
+	func_exit();
+}
+
+
+/* The standard serial_close would become shorter if you'd wrap it like
+   this. 
+   rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;}
+ */
+static void rio_close(void *ptr)
+{
+	struct Port *PortP;
+
+	func_enter();
+
+	PortP = (struct Port *) ptr;
+
+	riotclose(ptr);
+
+	if (PortP->gs.port.count) {
+		printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.port.count);
+		PortP->gs.port.count = 0;
+	}
+
+	PortP->gs.port.tty = NULL;
+	func_exit();
+}
+
+
+
+static long rio_fw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	int rc = 0;
+	func_enter();
+
+	/* The "dev" argument isn't used. */
+	mutex_lock(&rio_fw_mutex);
+	rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN));
+	mutex_unlock(&rio_fw_mutex);
+
+	func_exit();
+	return rc;
+}
+
+extern int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);
+
+static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int rc;
+	struct Port *PortP;
+	int ival;
+
+	func_enter();
+
+	PortP = (struct Port *) tty->driver_data;
+
+	rc = 0;
+	switch (cmd) {
+	case TIOCSSOFTCAR:
+		if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
+			tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0);
+		}
+		break;
+	case TIOCGSERIAL:
+		rc = -EFAULT;
+		if (access_ok(VERIFY_WRITE, argp, sizeof(struct serial_struct)))
+			rc = gs_getserial(&PortP->gs, argp);
+		break;
+	case TCSBRK:
+		if (PortP->State & RIO_DELETED) {
+			rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+			rc = -EIO;
+		} else {
+			if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
+					RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+				rc = -EIO;
+			}
+		}
+		break;
+	case TCSBRKP:
+		if (PortP->State & RIO_DELETED) {
+			rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
+			rc = -EIO;
+		} else {
+			int l;
+			l = arg ? arg * 100 : 250;
+			if (l > 255)
+				l = 255;
+			if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
+					arg ? arg * 100 : 250) == RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
+				rc = -EIO;
+			}
+		}
+		break;
+	case TIOCSSERIAL:
+		rc = -EFAULT;
+		if (access_ok(VERIFY_READ, argp, sizeof(struct serial_struct)))
+			rc = gs_setserial(&PortP->gs, argp);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	func_exit();
+	return rc;
+}
+
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation. 
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself.  This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here.  When we come to read characters from the
+ * rx buffers on the card (rio_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in rio_rx_throt[]). 
+ * If it can't we simply don't remove chars from the cards buffer. 
+ * When the tty layer can accept chars, we again note that here and when
+ * rio_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void rio_throttle(struct tty_struct *tty)
+{
+	struct Port *port = (struct Port *) tty->driver_data;
+
+	func_enter();
+	/* If the port is using any type of input flow
+	 * control then throttle the port.
+	 */
+
+	if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
+		port->State |= RIO_THROTTLE_RX;
+	}
+
+	func_exit();
+}
+
+
+static void rio_unthrottle(struct tty_struct *tty)
+{
+	struct Port *port = (struct Port *) tty->driver_data;
+
+	func_enter();
+	/* Always unthrottle even if flow control is not enabled on
+	 * this port in case we disabled flow control while the port
+	 * was throttled
+	 */
+
+	port->State &= ~RIO_THROTTLE_RX;
+
+	func_exit();
+	return;
+}
+
+
+
+
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+
+static struct vpd_prom *get_VPD_PROM(struct Host *hp)
+{
+	static struct vpd_prom vpdp;
+	char *p;
+	int i;
+
+	func_enter();
+	rio_dprintk(RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", hp->Caddr + RIO_VPD_ROM);
+
+	p = (char *) &vpdp;
+	for (i = 0; i < sizeof(struct vpd_prom); i++)
+		*p++ = readb(hp->Caddr + RIO_VPD_ROM + i * 2);
+	/* read_rio_byte (hp, RIO_VPD_ROM + i*2); */
+
+	/* Terminate the identifier string.
+	 *** requires one extra byte in struct vpd_prom *** */
+	*p++ = 0;
+
+	if (rio_debug & RIO_DEBUG_PROBE)
+		my_hd((char *) &vpdp, 0x20);
+
+	func_exit();
+
+	return &vpdp;
+}
+
+static const struct tty_operations rio_ops = {
+	.open = riotopen,
+	.close = gs_close,
+	.write = gs_write,
+	.put_char = gs_put_char,
+	.flush_chars = gs_flush_chars,
+	.write_room = gs_write_room,
+	.chars_in_buffer = gs_chars_in_buffer,
+	.flush_buffer = gs_flush_buffer,
+	.ioctl = rio_ioctl,
+	.throttle = rio_throttle,
+	.unthrottle = rio_unthrottle,
+	.set_termios = gs_set_termios,
+	.stop = gs_stop,
+	.start = gs_start,
+	.hangup = gs_hangup,
+};
+
+static int rio_init_drivers(void)
+{
+	int error = -ENOMEM;
+
+	rio_driver = alloc_tty_driver(256);
+	if (!rio_driver)
+		goto out;
+	rio_driver2 = alloc_tty_driver(256);
+	if (!rio_driver2)
+		goto out1;
+
+	func_enter();
+
+	rio_driver->owner = THIS_MODULE;
+	rio_driver->driver_name = "specialix_rio";
+	rio_driver->name = "ttySR";
+	rio_driver->major = RIO_NORMAL_MAJOR0;
+	rio_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	rio_driver->subtype = SERIAL_TYPE_NORMAL;
+	rio_driver->init_termios = tty_std_termios;
+	rio_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	rio_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(rio_driver, &rio_ops);
+
+	rio_driver2->owner = THIS_MODULE;
+	rio_driver2->driver_name = "specialix_rio";
+	rio_driver2->name = "ttySR";
+	rio_driver2->major = RIO_NORMAL_MAJOR1;
+	rio_driver2->type = TTY_DRIVER_TYPE_SERIAL;
+	rio_driver2->subtype = SERIAL_TYPE_NORMAL;
+	rio_driver2->init_termios = tty_std_termios;
+	rio_driver2->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	rio_driver2->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(rio_driver2, &rio_ops);
+
+	rio_dprintk(RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
+
+	if ((error = tty_register_driver(rio_driver)))
+		goto out2;
+	if ((error = tty_register_driver(rio_driver2)))
+		goto out3;
+	func_exit();
+	return 0;
+      out3:
+	tty_unregister_driver(rio_driver);
+      out2:
+	put_tty_driver(rio_driver2);
+      out1:
+	put_tty_driver(rio_driver);
+      out:
+	printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n", error);
+	return 1;
+}
+
+static const struct tty_port_operations rio_port_ops = {
+	.carrier_raised = rio_carrier_raised,
+};
+
+static int rio_init_datastructures(void)
+{
+	int i;
+	struct Port *port;
+	func_enter();
+
+	/* Many drivers statically allocate the maximum number of ports
+	   There is no reason not to allocate them dynamically. Is there? -- REW */
+	/* However, the RIO driver allows users to configure their first
+	   RTA as the ports numbered 504-511. We therefore need to allocate
+	   the whole range. :-(   -- REW */
+
+#define RI_SZ   sizeof(struct rio_info)
+#define HOST_SZ sizeof(struct Host)
+#define PORT_SZ sizeof(struct Port *)
+#define TMIO_SZ sizeof(struct termios *)
+	rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ);
+
+	if (!(p = kzalloc(RI_SZ, GFP_KERNEL)))
+		goto free0;
+	if (!(p->RIOHosts = kzalloc(RIO_HOSTS * HOST_SZ, GFP_KERNEL)))
+		goto free1;
+	if (!(p->RIOPortp = kzalloc(RIO_PORTS * PORT_SZ, GFP_KERNEL)))
+		goto free2;
+	p->RIOConf = RIOConf;
+	rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
+
+#if 1
+	for (i = 0; i < RIO_PORTS; i++) {
+		port = p->RIOPortp[i] = kzalloc(sizeof(struct Port), GFP_KERNEL);
+		if (!port) {
+			goto free6;
+		}
+		rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
+		tty_port_init(&port->gs.port);
+		port->gs.port.ops = &rio_port_ops;
+		port->PortNum = i;
+		port->gs.magic = RIO_MAGIC;
+		port->gs.close_delay = HZ / 2;
+		port->gs.closing_wait = 30 * HZ;
+		port->gs.rd = &rio_real_driver;
+		spin_lock_init(&port->portSem);
+	}
+#else
+	/* We could postpone initializing them to when they are configured. */
+#endif
+
+
+
+	if (rio_debug & RIO_DEBUG_INIT) {
+		my_hd(&rio_real_driver, sizeof(rio_real_driver));
+	}
+
+
+	func_exit();
+	return 0;
+
+      free6:for (i--; i >= 0; i--)
+		kfree(p->RIOPortp[i]);
+/*free5:
+ free4:
+ free3:*/ kfree(p->RIOPortp);
+      free2:kfree(p->RIOHosts);
+      free1:
+	rio_dprintk(RIO_DEBUG_INIT, "Not enough memory! %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
+	kfree(p);
+      free0:
+	return -ENOMEM;
+}
+
+static void __exit rio_release_drivers(void)
+{
+	func_enter();
+	tty_unregister_driver(rio_driver2);
+	tty_unregister_driver(rio_driver);
+	put_tty_driver(rio_driver2);
+	put_tty_driver(rio_driver);
+	func_exit();
+}
+
+
+#ifdef CONFIG_PCI
+ /* This was written for SX, but applies to RIO too...
+    (including bugs....)
+
+    There is another bit besides Bit 17. Turning that bit off
+    (on boards shipped with the fix in the eeprom) results in a 
+    hang on the next access to the card. 
+  */
+
+ /******************************************************** 
+ * Setting bit 17 in the CNTRL register of the PLX 9050  * 
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon  *
+ * multiprocessor systems with the NX chipset.    -- NV  *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+   EEprom.  As the bit is read/write for the CPU, we can fix it here,
+   if we detect that it isn't set correctly. -- REW */
+
+static void fix_rio_pci(struct pci_dev *pdev)
+{
+	unsigned long hwbase;
+	unsigned char __iomem *rebase;
+	unsigned int t;
+
+#define CNTRL_REG_OFFSET        0x50
+#define CNTRL_REG_GOODVALUE     0x18260000
+
+	hwbase = pci_resource_start(pdev, 0);
+	rebase = ioremap(hwbase, 0x80);
+	t = readl(rebase + CNTRL_REG_OFFSET);
+	if (t != CNTRL_REG_GOODVALUE) {
+		printk(KERN_DEBUG "rio: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
+		writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
+	}
+	iounmap(rebase);
+}
+#endif
+
+
+static int __init rio_init(void)
+{
+	int found = 0;
+	int i;
+	struct Host *hp;
+	int retval;
+	struct vpd_prom *vpdp;
+	int okboard;
+
+#ifdef CONFIG_PCI
+	struct pci_dev *pdev = NULL;
+	unsigned short tshort;
+#endif
+
+	func_enter();
+	rio_dprintk(RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n", rio_debug);
+
+	if (abs((long) (&rio_debug) - rio_debug) < 0x10000) {
+		printk(KERN_WARNING "rio: rio_debug is an address, instead of a value. " "Assuming -1. Was %x/%p.\n", rio_debug, &rio_debug);
+		rio_debug = -1;
+	}
+
+	if (misc_register(&rio_fw_device) < 0) {
+		printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n");
+		return -EIO;
+	}
+
+	retval = rio_init_datastructures();
+	if (retval < 0) {
+		misc_deregister(&rio_fw_device);
+		return retval;
+	}
+#ifdef CONFIG_PCI
+	/* First look for the JET devices: */
+	while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) {
+		u32 tint;
+
+		if (pci_enable_device(pdev))
+			continue;
+
+		/* Specialix has a whole bunch of cards with
+		   0x2000 as the device ID. They say its because
+		   the standard requires it. Stupid standard. */
+		/* It seems that reading a word doesn't work reliably on 2.0.
+		   Also, reading a non-aligned dword doesn't work. So we read the
+		   whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
+		   ourselves */
+		pci_read_config_dword(pdev, 0x2c, &tint);
+		tshort = (tint >> 16) & 0xffff;
+		rio_dprintk(RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
+		if (tshort != 0x0100) {
+			rio_dprintk(RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", tshort);
+			continue;
+		}
+		rio_dprintk(RIO_DEBUG_PROBE, "cp1\n");
+
+		hp = &p->RIOHosts[p->RIONumHosts];
+		hp->PaddrP = pci_resource_start(pdev, 2);
+		hp->Ivec = pdev->irq;
+		if (((1 << hp->Ivec) & rio_irqmask) == 0)
+			hp->Ivec = 0;
+		hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+		hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+		hp->Type = RIO_PCI;
+		hp->Copy = rio_copy_to_card;
+		hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+		spin_lock_init(&hp->HostLock);
+		rio_reset_interrupt(hp);
+		rio_start_card_running(hp);
+
+		rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
+		if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
+			rio_dprintk(RIO_DEBUG_INIT, "Done RIOBoardTest\n");
+			writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+			p->RIOHosts[p->RIONumHosts].UniqueNum =
+			    ((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
+			    ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
+			rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+			fix_rio_pci(pdev);
+
+			p->RIOHosts[p->RIONumHosts].pdev = pdev;
+			pci_dev_get(pdev);
+
+			p->RIOLastPCISearch = 0;
+			p->RIONumHosts++;
+			found++;
+		} else {
+			iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
+			p->RIOHosts[p->RIONumHosts].Caddr = NULL;
+		}
+	}
+
+	/* Then look for the older PCI card.... : */
+
+	/* These older PCI cards have problems (only byte-mode access is
+	   supported), which makes them a bit awkward to support.
+	   They also have problems sharing interrupts. Be careful.
+	   (The driver now refuses to share interrupts for these
+	   cards. This should be sufficient).
+	 */
+
+	/* Then look for the older RIO/PCI devices: */
+	while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) {
+		if (pci_enable_device(pdev))
+			continue;
+
+#ifdef CONFIG_RIO_OLDPCI
+		hp = &p->RIOHosts[p->RIONumHosts];
+		hp->PaddrP = pci_resource_start(pdev, 0);
+		hp->Ivec = pdev->irq;
+		if (((1 << hp->Ivec) & rio_irqmask) == 0)
+			hp->Ivec = 0;
+		hp->Ivec |= 0x8000;	/* Mark as non-sharable */
+		hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+		hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+		hp->Type = RIO_PCI;
+		hp->Copy = rio_copy_to_card;
+		hp->Mode = RIO_PCI_BOOT_FROM_RAM;
+		spin_lock_init(&hp->HostLock);
+
+		rio_dprintk(RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec);
+		rio_dprintk(RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode);
+
+		rio_reset_interrupt(hp);
+		rio_start_card_running(hp);
+		rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
+		if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
+			writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+			p->RIOHosts[p->RIONumHosts].UniqueNum =
+			    ((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
+			    ((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
+			rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+			p->RIOHosts[p->RIONumHosts].pdev = pdev;
+			pci_dev_get(pdev);
+
+			p->RIOLastPCISearch = 0;
+			p->RIONumHosts++;
+			found++;
+		} else {
+			iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
+			p->RIOHosts[p->RIONumHosts].Caddr = NULL;
+		}
+#else
+		printk(KERN_ERR "Found an older RIO PCI card, but the driver is not " "compiled to support it.\n");
+#endif
+	}
+#endif				/* PCI */
+
+	/* Now probe for ISA cards... */
+	for (i = 0; i < NR_RIO_ADDRS; i++) {
+		hp = &p->RIOHosts[p->RIONumHosts];
+		hp->PaddrP = rio_probe_addrs[i];
+		/* There was something about the IRQs of these cards. 'Forget what.--REW */
+		hp->Ivec = 0;
+		hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
+		hp->CardP = (struct DpRam __iomem *) hp->Caddr;
+		hp->Type = RIO_AT;
+		hp->Copy = rio_copy_to_card;	/* AT card PCI???? - PVDL
+                                         * -- YES! this is now a normal copy. Only the
+					 * old PCI card uses the special PCI copy.
+					 * Moreover, the ISA card will work with the
+					 * special PCI copy anyway. -- REW */
+		hp->Mode = 0;
+		spin_lock_init(&hp->HostLock);
+
+		vpdp = get_VPD_PROM(hp);
+		rio_dprintk(RIO_DEBUG_PROBE, "Got VPD ROM\n");
+		okboard = 0;
+		if ((strncmp(vpdp->identifier, RIO_ISA_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA2_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA3_IDENT, 16) == 0)) {
+			/* Board is present... */
+			if (RIOBoardTest(hp->PaddrP, hp->Caddr, RIO_AT, 0) == 0) {
+				/* ... and feeling fine!!!! */
+				rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+				if (RIOAssignAT(p, hp->PaddrP, hp->Caddr, 0)) {
+					rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, host%d uniqid = %x.\n", p->RIONumHosts, p->RIOHosts[p->RIONumHosts - 1].UniqueNum);
+					okboard++;
+					found++;
+				}
+			}
+
+			if (!okboard) {
+				iounmap(hp->Caddr);
+				hp->Caddr = NULL;
+			}
+		}
+	}
+
+
+	for (i = 0; i < p->RIONumHosts; i++) {
+		hp = &p->RIOHosts[i];
+		if (hp->Ivec) {
+			int mode = IRQF_SHARED;
+			if (hp->Ivec & 0x8000) {
+				mode = 0;
+				hp->Ivec &= 0x7fff;
+			}
+			rio_dprintk(RIO_DEBUG_INIT, "Requesting interrupt hp: %p rio_interrupt: %d Mode: %x\n", hp, hp->Ivec, hp->Mode);
+			retval = request_irq(hp->Ivec, rio_interrupt, mode, "rio", hp);
+			rio_dprintk(RIO_DEBUG_INIT, "Return value from request_irq: %d\n", retval);
+			if (retval) {
+				printk(KERN_ERR "rio: Cannot allocate irq %d.\n", hp->Ivec);
+				hp->Ivec = 0;
+			}
+			rio_dprintk(RIO_DEBUG_INIT, "Got irq %d.\n", hp->Ivec);
+			if (hp->Ivec != 0) {
+				rio_dprintk(RIO_DEBUG_INIT, "Enabling interrupts on rio card.\n");
+				hp->Mode |= RIO_PCI_INT_ENABLE;
+			} else
+				hp->Mode &= ~RIO_PCI_INT_ENABLE;
+			rio_dprintk(RIO_DEBUG_INIT, "New Mode: %x\n", hp->Mode);
+			rio_start_card_running(hp);
+		}
+		/* Init the timer "always" to make sure that it can safely be
+		   deleted when we unload... */
+
+		setup_timer(&hp->timer, rio_pollfunc, i);
+		if (!hp->Ivec) {
+			rio_dprintk(RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", rio_poll);
+			mod_timer(&hp->timer, jiffies + rio_poll);
+		}
+	}
+
+	if (found) {
+		rio_dprintk(RIO_DEBUG_INIT, "rio: total of %d boards detected.\n", found);
+		rio_init_drivers();
+	} else {
+		/* deregister the misc device we created earlier */
+		misc_deregister(&rio_fw_device);
+	}
+
+	func_exit();
+	return found ? 0 : -EIO;
+}
+
+
+static void __exit rio_exit(void)
+{
+	int i;
+	struct Host *hp;
+
+	func_enter();
+
+	for (i = 0, hp = p->RIOHosts; i < p->RIONumHosts; i++, hp++) {
+		RIOHostReset(hp->Type, hp->CardP, hp->Slot);
+		if (hp->Ivec) {
+			free_irq(hp->Ivec, hp);
+			rio_dprintk(RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
+		}
+		/* It is safe/allowed to del_timer a non-active timer */
+		del_timer_sync(&hp->timer);
+		if (hp->Caddr)
+			iounmap(hp->Caddr);
+		if (hp->Type == RIO_PCI)
+			pci_dev_put(hp->pdev);
+	}
+
+	if (misc_deregister(&rio_fw_device) < 0) {
+		printk(KERN_INFO "rio: couldn't deregister control-device\n");
+	}
+
+
+	rio_dprintk(RIO_DEBUG_CLEANUP, "Cleaning up drivers\n");
+
+	rio_release_drivers();
+
+	/* Release dynamically allocated memory */
+	kfree(p->RIOPortp);
+	kfree(p->RIOHosts);
+	kfree(p);
+
+	func_exit();
+}
+
+module_init(rio_init);
+module_exit(rio_exit);
diff --git a/drivers/staging/generic_serial/rio/rio_linux.h b/drivers/staging/generic_serial/rio/rio_linux.h
new file mode 100644
index 0000000..7f26cd7
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rio_linux.h
@@ -0,0 +1,197 @@
+
+/*
+ *  rio_linux.h
+ *
+ *  Copyright (C) 1998,1999,2000 R.E.Wolff@BitWizard.nl
+ *
+ *      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.
+ *
+ *  RIO serial driver.
+ *
+ *  Version 1.0 -- July, 1999. 
+ * 
+ */
+
+#define RIO_NBOARDS        4
+#define RIO_PORTSPERBOARD 128
+#define RIO_NPORTS        (RIO_NBOARDS * RIO_PORTSPERBOARD)
+
+#define MODEM_SUPPORT
+
+#ifdef __KERNEL__
+
+#define RIO_MAGIC 0x12345678
+
+
+struct vpd_prom {
+	unsigned short id;
+	char hwrev;
+	char hwass;
+	int uniqid;
+	char myear;
+	char mweek;
+	char hw_feature[5];
+	char oem_id;
+	char identifier[16];
+};
+
+
+#define RIO_DEBUG_ALL           0xffffffff
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+
+#endif				/* __KERNEL__ */
+
+
+#define RIO_BOARD_INTR_LOCK  1
+
+
+#ifndef RIOCTL_MISC_MINOR
+/* Allow others to gather this into "major.h" or something like that */
+#define RIOCTL_MISC_MINOR    169
+#endif
+
+
+/* Allow us to debug "in the field" without requiring clients to
+   recompile.... */
+#if 1
+#define rio_spin_lock_irqsave(sem, flags) do { \
+	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlockirqsave: %p %s:%d\n", \
+	                                sem, __FILE__, __LINE__);\
+	spin_lock_irqsave(sem, flags);\
+	} while (0)
+
+#define rio_spin_unlock_irqrestore(sem, flags) do { \
+	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlockirqrestore: %p %s:%d\n",\
+	                                sem, __FILE__, __LINE__);\
+	spin_unlock_irqrestore(sem, flags);\
+	} while (0)
+
+#define rio_spin_lock(sem) do { \
+	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinlock: %p %s:%d\n",\
+	                                sem, __FILE__, __LINE__);\
+	spin_lock(sem);\
+	} while (0)
+
+#define rio_spin_unlock(sem) do { \
+	rio_dprintk (RIO_DEBUG_SPINLOCK, "spinunlock: %p %s:%d\n",\
+	                                sem, __FILE__, __LINE__);\
+	spin_unlock(sem);\
+	} while (0)
+#else
+#define rio_spin_lock_irqsave(sem, flags) \
+            spin_lock_irqsave(sem, flags)
+
+#define rio_spin_unlock_irqrestore(sem, flags) \
+            spin_unlock_irqrestore(sem, flags)
+
+#define rio_spin_lock(sem) \
+            spin_lock(sem)
+
+#define rio_spin_unlock(sem) \
+            spin_unlock(sem)
+
+#endif
+
+
+
+#ifdef CONFIG_RIO_OLDPCI
+static inline void __iomem *rio_memcpy_toio(void __iomem *dummy, void __iomem *dest, void *source, int n)
+{
+	char __iomem *dst = dest;
+	char *src = source;
+
+	while (n--) {
+		writeb(*src++, dst++);
+		(void) readb(dummy);
+	}
+
+	return dest;
+}
+
+static inline void __iomem *rio_copy_toio(void __iomem *dest, void *source, int n)
+{
+	char __iomem *dst = dest;
+	char *src = source;
+
+	while (n--)
+		writeb(*src++, dst++);
+
+	return dest;
+}
+
+
+static inline void *rio_memcpy_fromio(void *dest, void __iomem *source, int n)
+{
+	char *dst = dest;
+	char __iomem *src = source;
+
+	while (n--)
+		*dst++ = readb(src++);
+
+	return dest;
+}
+
+#else
+#define rio_memcpy_toio(dummy,dest,source,n)   memcpy_toio(dest, source, n)
+#define rio_copy_toio   		       memcpy_toio
+#define rio_memcpy_fromio                      memcpy_fromio
+#endif
+
+#define DEBUG 1
+
+
+/* 
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile... 
+*/
+
+#ifdef DEBUG
+#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__)
+#define func_exit()  rio_dprintk (RIO_DEBUG_FLOW, "rio: exit  %s\n", __func__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line)
+#else
+#define rio_dprintk(f, str...)	/* nothing */
+#define func_enter()
+#define func_exit()
+#define func_enter2()
+#endif
diff --git a/drivers/staging/generic_serial/rio/rioboard.h b/drivers/staging/generic_serial/rio/rioboard.h
new file mode 100644
index 0000000..2522300
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioboard.h
@@ -0,0 +1,275 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	RIO Host Card Hardware Definitions	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	26th April 1999				*/
+/*									*/
+/*	Version		:	1.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1999	*
+ *
+ *      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.
+ *									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the RIO board hardware	*/
+/*									*/
+/************************************************************************/
+
+#ifndef	_rioboard_h		/* If RIOBOARD.H not already defined */
+#define	_rioboard_h    1
+
+/*****************************************************************************
+***********************                                ***********************
+***********************   Hardware Control Registers   ***********************
+***********************                                ***********************
+*****************************************************************************/
+
+/* Hardware Registers... */
+
+#define	RIO_REG_BASE	0x7C00	/* Base of control registers */
+
+#define	RIO_CONFIG	RIO_REG_BASE + 0x0000	/* WRITE: Configuration Register */
+#define	RIO_INTSET	RIO_REG_BASE + 0x0080	/* WRITE: Interrupt Set */
+#define	RIO_RESET	RIO_REG_BASE + 0x0100	/* WRITE: Host Reset */
+#define	RIO_INTRESET	RIO_REG_BASE + 0x0180	/* WRITE: Interrupt Reset */
+
+#define	RIO_VPD_ROM	RIO_REG_BASE + 0x0000	/* READ: Vital Product Data ROM */
+#define	RIO_INTSTAT	RIO_REG_BASE + 0x0080	/* READ: Interrupt Status (Jet boards only) */
+#define	RIO_RESETSTAT	RIO_REG_BASE + 0x0100	/* READ: Reset Status (Jet boards only) */
+
+/* RIO_VPD_ROM definitions... */
+#define	VPD_SLX_ID1	0x00	/* READ: Specialix Identifier #1 */
+#define	VPD_SLX_ID2	0x01	/* READ: Specialix Identifier #2 */
+#define	VPD_HW_REV	0x02	/* READ: Hardware Revision */
+#define	VPD_HW_ASSEM	0x03	/* READ: Hardware Assembly Level */
+#define	VPD_UNIQUEID4	0x04	/* READ: Unique Identifier #4 */
+#define	VPD_UNIQUEID3	0x05	/* READ: Unique Identifier #3 */
+#define	VPD_UNIQUEID2	0x06	/* READ: Unique Identifier #2 */
+#define	VPD_UNIQUEID1	0x07	/* READ: Unique Identifier #1 */
+#define	VPD_MANU_YEAR	0x08	/* READ: Year Of Manufacture (0 = 1970) */
+#define	VPD_MANU_WEEK	0x09	/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	VPD_HWFEATURE1	0x0A	/* READ: Hardware Feature Byte 1 */
+#define	VPD_HWFEATURE2	0x0B	/* READ: Hardware Feature Byte 2 */
+#define	VPD_HWFEATURE3	0x0C	/* READ: Hardware Feature Byte 3 */
+#define	VPD_HWFEATURE4	0x0D	/* READ: Hardware Feature Byte 4 */
+#define	VPD_HWFEATURE5	0x0E	/* READ: Hardware Feature Byte 5 */
+#define	VPD_OEMID	0x0F	/* READ: OEM Identifier */
+#define	VPD_IDENT	0x10	/* READ: Identifier string (16 bytes) */
+#define	VPD_IDENT_LEN	0x10
+
+/* VPD ROM Definitions... */
+#define	SLX_ID1		0x4D
+#define	SLX_ID2		0x98
+
+#define	PRODUCT_ID(a)	((a>>4)&0xF)	/* Use to obtain Product ID from VPD_UNIQUEID1 */
+
+#define	ID_SX_ISA	0x2
+#define	ID_RIO_EISA	0x3
+#define	ID_SX_PCI	0x5
+#define	ID_SX_EISA	0x7
+#define	ID_RIO_RTA16	0x9
+#define	ID_RIO_ISA	0xA
+#define	ID_RIO_MCA	0xB
+#define	ID_RIO_SBUS	0xC
+#define	ID_RIO_PCI	0xD
+#define	ID_RIO_RTA8	0xE
+
+/* Transputer bootstrap definitions... */
+
+#define	BOOTLOADADDR		(0x8000 - 6)
+#define	BOOTINDICATE		(0x8000 - 2)
+
+/* Firmware load position... */
+
+#define	FIRMWARELOADADDR	0x7C00	/* Firmware is loaded _before_ this address */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev1) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_ISA_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_ISA_CFG_IRQMASK	0x30	/* Interrupt mask */
+#define	  RIO_ISA_CFG_IRQ12	0x10	/* Interrupt Level 12 */
+#define	  RIO_ISA_CFG_IRQ11	0x20	/* Interrupt Level 11 */
+#define	  RIO_ISA_CFG_IRQ9	0x30	/* Interrupt Level 9 */
+#define	RIO_ISA_CFG_LINK20	0x40	/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA_CFG_WAITSTATE0	0x80	/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                    *****************************
+*****************************   RIO (Rev2) ISA   *****************************
+*****************************                    *****************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA2_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_ISA2_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_ISA2_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_ISA2_CFG_INTENABLE	0x04	/* Interrupt enable, else disable */
+#define	RIO_ISA2_CFG_16BIT	0x08	/* 16bit mode, else 8bit */
+#define	RIO_ISA2_CFG_IRQMASK	0x30	/* Interrupt mask */
+#define	  RIO_ISA2_CFG_IRQ15	0x00	/* Interrupt Level 15 */
+#define	  RIO_ISA2_CFG_IRQ12	0x10	/* Interrupt Level 12 */
+#define	  RIO_ISA2_CFG_IRQ11	0x20	/* Interrupt Level 11 */
+#define	  RIO_ISA2_CFG_IRQ9	0x30	/* Interrupt Level 9 */
+#define	RIO_ISA2_CFG_LINK20	0x40	/* 20Mbps link, else 10Mbps */
+#define	RIO_ISA2_CFG_WAITSTATE0	0x80	/* 0 waitstates, else 1 */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) ISA   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_ISA3_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_ISA3_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_ISA3_CFG_INTENABLE	0x04	/* Interrupt enable, else disable */
+#define	RIO_ISA32_CFG_IRQMASK	0xF30	/* Interrupt mask */
+#define	  RIO_ISA3_CFG_IRQ15	0xF0	/* Interrupt Level 15 */
+#define	  RIO_ISA3_CFG_IRQ12	0xC0	/* Interrupt Level 12 */
+#define	  RIO_ISA3_CFG_IRQ11	0xB0	/* Interrupt Level 11 */
+#define	  RIO_ISA3_CFG_IRQ10	0xA0	/* Interrupt Level 10 */
+#define	  RIO_ISA3_CFG_IRQ9	0x90	/* Interrupt Level 9 */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO MCA   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_MCA_IDENT	"JBJGPGGHINSMJPJR"
+
+#define	RIO_MCA_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_MCA_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_MCA_CFG_LINK20	0x40	/* 20Mbps link, else 10Mbps */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO EISA   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* EISA Configuration Space Definitions... */
+#define	EISA_PRODUCT_ID1	0xC80
+#define	EISA_PRODUCT_ID2	0xC81
+#define	EISA_PRODUCT_NUMBER	0xC82
+#define	EISA_REVISION_NUMBER	0xC83
+#define	EISA_CARD_ENABLE	0xC84
+#define	EISA_VPD_UNIQUEID4	0xC88	/* READ: Unique Identifier #4 */
+#define	EISA_VPD_UNIQUEID3	0xC8A	/* READ: Unique Identifier #3 */
+#define	EISA_VPD_UNIQUEID2	0xC90	/* READ: Unique Identifier #2 */
+#define	EISA_VPD_UNIQUEID1	0xC92	/* READ: Unique Identifier #1 */
+#define	EISA_VPD_MANU_YEAR	0xC98	/* READ: Year Of Manufacture (0 = 1970) */
+#define	EISA_VPD_MANU_WEEK	0xC9A	/* READ: Week Of Manufacture (0 = week 1 Jan) */
+#define	EISA_MEM_ADDR_23_16	0xC00
+#define	EISA_MEM_ADDR_31_24	0xC01
+#define	EISA_RIO_CONFIG		0xC02	/* WRITE: Configuration Register */
+#define	EISA_RIO_INTSET		0xC03	/* WRITE: Interrupt Set */
+#define	EISA_RIO_INTRESET	0xC03	/* READ:  Interrupt Reset */
+
+/* Control Register Definitions... */
+#define	RIO_EISA_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_EISA_CFG_LINK20	0x02	/* 20Mbps link, else 10Mbps */
+#define	RIO_EISA_CFG_BUSENABLE	0x04	/* Enable processor bus */
+#define	RIO_EISA_CFG_PROCRUN	0x08	/* Processor running, else reset */
+#define	RIO_EISA_CFG_IRQMASK	0xF0	/* Interrupt mask */
+#define	  RIO_EISA_CFG_IRQ15	0xF0	/* Interrupt Level 15 */
+#define	  RIO_EISA_CFG_IRQ14	0xE0	/* Interrupt Level 14 */
+#define	  RIO_EISA_CFG_IRQ12	0xC0	/* Interrupt Level 12 */
+#define	  RIO_EISA_CFG_IRQ11	0xB0	/* Interrupt Level 11 */
+#define	  RIO_EISA_CFG_IRQ10	0xA0	/* Interrupt Level 10 */
+#define	  RIO_EISA_CFG_IRQ9	0x90	/* Interrupt Level 9 */
+#define	  RIO_EISA_CFG_IRQ7	0x70	/* Interrupt Level 7 */
+#define	  RIO_EISA_CFG_IRQ6	0x60	/* Interrupt Level 6 */
+#define	  RIO_EISA_CFG_IRQ5	0x50	/* Interrupt Level 5 */
+#define	  RIO_EISA_CFG_IRQ4	0x40	/* Interrupt Level 4 */
+#define	  RIO_EISA_CFG_IRQ3	0x30	/* Interrupt Level 3 */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   RIO SBus   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_SBUS_IDENT	"JBPGK#\0\0\0\0\0\0\0\0\0\0"
+
+#define	RIO_SBUS_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_SBUS_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_SBUS_CFG_INTENABLE	0x04	/* Interrupt enable, else disable */
+#define	RIO_SBUS_CFG_IRQMASK	0x38	/* Interrupt mask */
+#define	  RIO_SBUS_CFG_IRQNONE	0x00	/* No Interrupt */
+#define	  RIO_SBUS_CFG_IRQ7	0x38	/* Interrupt Level 7 */
+#define	  RIO_SBUS_CFG_IRQ6	0x30	/* Interrupt Level 6 */
+#define	  RIO_SBUS_CFG_IRQ5	0x28	/* Interrupt Level 5 */
+#define	  RIO_SBUS_CFG_IRQ4	0x20	/* Interrupt Level 4 */
+#define	  RIO_SBUS_CFG_IRQ3	0x18	/* Interrupt Level 3 */
+#define	  RIO_SBUS_CFG_IRQ2	0x10	/* Interrupt Level 2 */
+#define	  RIO_SBUS_CFG_IRQ1	0x08	/* Interrupt Level 1 */
+#define	RIO_SBUS_CFG_LINK20	0x40	/* 20Mbps link, else 10Mbps */
+#define	RIO_SBUS_CFG_PROC25	0x80	/* 25Mhz processor clock, else 20Mhz */
+
+/*****************************************************************************
+*********************************             ********************************
+*********************************   RIO PCI   ********************************
+*********************************             ********************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI_IDENT	"ECDDPGJGJHJRGSK#"
+
+#define	RIO_PCI_CFG_BOOTRAM	0x01	/* Boot from RAM, else Link */
+#define	RIO_PCI_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_PCI_CFG_INTENABLE	0x04	/* Interrupt enable, else disable */
+#define	RIO_PCI_CFG_LINK20	0x40	/* 20Mbps link, else 10Mbps */
+#define	RIO_PCI_CFG_PROC25	0x80	/* 25Mhz processor clock, else 20Mhz */
+
+/* PCI Definitions... */
+#define	SPX_VENDOR_ID		0x11CB	/* Assigned by the PCI SIG */
+#define	SPX_DEVICE_ID		0x8000	/* RIO bridge boards */
+#define	SPX_PLXDEVICE_ID	0x2000	/* PLX bridge boards */
+#define	SPX_SUB_VENDOR_ID	SPX_VENDOR_ID	/* Same as vendor id */
+#define	RIO_SUB_SYS_ID		0x0800	/* RIO PCI board */
+
+/*****************************************************************************
+*****************************                   ******************************
+*****************************   RIO (Jet) PCI   ******************************
+*****************************                   ******************************
+*****************************************************************************/
+
+/* Control Register Definitions... */
+#define	RIO_PCI2_IDENT	"JET HOST BY KEV#"
+
+#define	RIO_PCI2_CFG_BUSENABLE	0x02	/* Enable processor bus */
+#define	RIO_PCI2_CFG_INTENABLE	0x04	/* Interrupt enable, else disable */
+
+/* PCI Definitions... */
+#define	RIO2_SUB_SYS_ID		0x0100	/* RIO (Jet) PCI board */
+
+#endif						/*_rioboard_h */
+
+/* End of RIOBOARD.H */
diff --git a/drivers/staging/generic_serial/rio/rioboot.c b/drivers/staging/generic_serial/rio/rioboot.c
new file mode 100644
index 0000000..d956dd3
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioboot.c
@@ -0,0 +1,1113 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioboot.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:36
+**	Retrieved	: 11/6/98 10:33:48
+**
+**  ident @(#)rioboot.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/termios.h>
+#include <linux/serial.h>
+#include <linux/vmalloc.h>
+#include <linux/generic_serial.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+
+static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP);
+
+static const unsigned char RIOAtVec2Ctrl[] = {
+	/* 0 */ INTERRUPT_DISABLE,
+	/* 1 */ INTERRUPT_DISABLE,
+	/* 2 */ INTERRUPT_DISABLE,
+	/* 3 */ INTERRUPT_DISABLE,
+	/* 4 */ INTERRUPT_DISABLE,
+	/* 5 */ INTERRUPT_DISABLE,
+	/* 6 */ INTERRUPT_DISABLE,
+	/* 7 */ INTERRUPT_DISABLE,
+	/* 8 */ INTERRUPT_DISABLE,
+	/* 9 */ IRQ_9 | INTERRUPT_ENABLE,
+	/* 10 */ INTERRUPT_DISABLE,
+	/* 11 */ IRQ_11 | INTERRUPT_ENABLE,
+	/* 12 */ IRQ_12 | INTERRUPT_ENABLE,
+	/* 13 */ INTERRUPT_DISABLE,
+	/* 14 */ INTERRUPT_DISABLE,
+	/* 15 */ IRQ_15 | INTERRUPT_ENABLE
+};
+
+/**
+ *	RIOBootCodeRTA		-	Load RTA boot code
+ *	@p: RIO to load
+ *	@rbp: Download descriptor
+ *
+ *	Called when the user process initiates booting of the card firmware.
+ *	Lads the firmware
+ */
+
+int RIOBootCodeRTA(struct rio_info *p, struct DownLoad * rbp)
+{
+	int offset;
+
+	func_enter();
+
+	rio_dprintk(RIO_DEBUG_BOOT, "Data at user address %p\n", rbp->DataP);
+
+	/*
+	 ** Check that we have set asside enough memory for this
+	 */
+	if (rbp->Count > SIXTY_FOUR_K) {
+		rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code Too Large!\n");
+		p->RIOError.Error = HOST_FILE_TOO_LARGE;
+		func_exit();
+		return -ENOMEM;
+	}
+
+	if (p->RIOBooting) {
+		rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot Code : BUSY BUSY BUSY!\n");
+		p->RIOError.Error = BOOT_IN_PROGRESS;
+		func_exit();
+		return -EBUSY;
+	}
+
+	/*
+	 ** The data we load in must end on a (RTA_BOOT_DATA_SIZE) byte boundary,
+	 ** so calculate how far we have to move the data up the buffer
+	 ** to achieve this.
+	 */
+	offset = (RTA_BOOT_DATA_SIZE - (rbp->Count % RTA_BOOT_DATA_SIZE)) % RTA_BOOT_DATA_SIZE;
+
+	/*
+	 ** Be clean, and clear the 'unused' portion of the boot buffer,
+	 ** because it will (eventually) be part of the Rta run time environment
+	 ** and so should be zeroed.
+	 */
+	memset(p->RIOBootPackets, 0, offset);
+
+	/*
+	 ** Copy the data from user space into the array
+	 */
+
+	if (copy_from_user(((u8 *)p->RIOBootPackets) + offset, rbp->DataP, rbp->Count)) {
+		rio_dprintk(RIO_DEBUG_BOOT, "Bad data copy from user space\n");
+		p->RIOError.Error = COPYIN_FAILED;
+		func_exit();
+		return -EFAULT;
+	}
+
+	/*
+	 ** Make sure that our copy of the size includes that offset we discussed
+	 ** earlier.
+	 */
+	p->RIONumBootPkts = (rbp->Count + offset) / RTA_BOOT_DATA_SIZE;
+	p->RIOBootCount = rbp->Count;
+
+	func_exit();
+	return 0;
+}
+
+/**
+ *	rio_start_card_running		-	host card start
+ *	@HostP: The RIO to kick off
+ *
+ *	Start a RIO processor unit running. Encapsulates the knowledge
+ *	of the card type.
+ */
+
+void rio_start_card_running(struct Host *HostP)
+{
+	switch (HostP->Type) {
+	case RIO_AT:
+		rio_dprintk(RIO_DEBUG_BOOT, "Start ISA card running\n");
+		writeb(BOOT_FROM_RAM | EXTERNAL_BUS_ON | HostP->Mode | RIOAtVec2Ctrl[HostP->Ivec & 0xF], &HostP->Control);
+		break;
+	case RIO_PCI:
+		/*
+		 ** PCI is much the same as MCA. Everything is once again memory
+		 ** mapped, so we are writing to memory registers instead of io
+		 ** ports.
+		 */
+		rio_dprintk(RIO_DEBUG_BOOT, "Start PCI card running\n");
+		writeb(PCITpBootFromRam | PCITpBusEnable | HostP->Mode, &HostP->Control);
+		break;
+	default:
+		rio_dprintk(RIO_DEBUG_BOOT, "Unknown host type %d\n", HostP->Type);
+		break;
+	}
+	return;
+}
+
+/*
+** Load in the host boot code - load it directly onto all halted hosts
+** of the correct type.
+**
+** Put your rubber pants on before messing with this code - even the magic
+** numbers have trouble understanding what they are doing here.
+*/
+
+int RIOBootCodeHOST(struct rio_info *p, struct DownLoad *rbp)
+{
+	struct Host *HostP;
+	u8 __iomem *Cad;
+	PARM_MAP __iomem *ParmMapP;
+	int RupN;
+	int PortN;
+	unsigned int host;
+	u8 __iomem *StartP;
+	u8 __iomem *DestP;
+	int wait_count;
+	u16 OldParmMap;
+	u16 offset;		/* It is very important that this is a u16 */
+	u8 *DownCode = NULL;
+	unsigned long flags;
+
+	HostP = NULL;		/* Assure the compiler we've initialized it */
+
+
+	/* Walk the hosts */
+	for (host = 0; host < p->RIONumHosts; host++) {
+		rio_dprintk(RIO_DEBUG_BOOT, "Attempt to boot host %d\n", host);
+		HostP = &p->RIOHosts[host];
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
+
+		/* Don't boot hosts already running */
+		if ((HostP->Flags & RUN_STATE) != RC_WAITING) {
+			rio_dprintk(RIO_DEBUG_BOOT, "%s %d already running\n", "Host", host);
+			continue;
+		}
+
+		/*
+		 ** Grab a pointer to the card (ioremapped)
+		 */
+		Cad = HostP->Caddr;
+
+		/*
+		 ** We are going to (try) and load in rbp->Count bytes.
+		 ** The last byte will reside at p->RIOConf.HostLoadBase-1;
+		 ** Therefore, we need to start copying at address
+		 ** (caddr+p->RIOConf.HostLoadBase-rbp->Count)
+		 */
+		StartP = &Cad[p->RIOConf.HostLoadBase - rbp->Count];
+
+		rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for host is %p\n", Cad);
+		rio_dprintk(RIO_DEBUG_BOOT, "kernel virtual address for download is %p\n", StartP);
+		rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
+		rio_dprintk(RIO_DEBUG_BOOT, "size of download is 0x%x\n", rbp->Count);
+
+		/* Make sure it fits */
+		if (p->RIOConf.HostLoadBase < rbp->Count) {
+			rio_dprintk(RIO_DEBUG_BOOT, "Bin too large\n");
+			p->RIOError.Error = HOST_FILE_TOO_LARGE;
+			func_exit();
+			return -EFBIG;
+		}
+		/*
+		 ** Ensure that the host really is stopped.
+		 ** Disable it's external bus & twang its reset line.
+		 */
+		RIOHostReset(HostP->Type, HostP->CardP, HostP->Slot);
+
+		/*
+		 ** Copy the data directly from user space to the SRAM.
+		 ** This ain't going to be none too clever if the download
+		 ** code is bigger than this segment.
+		 */
+		rio_dprintk(RIO_DEBUG_BOOT, "Copy in code\n");
+
+		/* Buffer to local memory as we want to use I/O space and
+		   some cards only do 8 or 16 bit I/O */
+
+		DownCode = vmalloc(rbp->Count);
+		if (!DownCode) {
+			p->RIOError.Error = NOT_ENOUGH_CORE_FOR_PCI_COPY;
+			func_exit();
+			return -ENOMEM;
+		}
+		if (copy_from_user(DownCode, rbp->DataP, rbp->Count)) {
+			kfree(DownCode);
+			p->RIOError.Error = COPYIN_FAILED;
+			func_exit();
+			return -EFAULT;
+		}
+		HostP->Copy(DownCode, StartP, rbp->Count);
+		vfree(DownCode);
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Copy completed\n");
+
+		/*
+		 **                     S T O P !
+		 **
+		 ** Upto this point the code has been fairly rational, and possibly
+		 ** even straight forward. What follows is a pile of crud that will
+		 ** magically turn into six bytes of transputer assembler. Normally
+		 ** you would expect an array or something, but, being me, I have
+		 ** chosen [been told] to use a technique whereby the startup code
+		 ** will be correct if we change the loadbase for the code. Which
+		 ** brings us onto another issue - the loadbase is the *end* of the
+		 ** code, not the start.
+		 **
+		 ** If I were you I wouldn't start from here.
+		 */
+
+		/*
+		 ** We now need to insert a short boot section into
+		 ** the memory at the end of Sram2. This is normally (de)composed
+		 ** of the last eight bytes of the download code. The
+		 ** download has been assembled/compiled to expect to be
+		 ** loaded from 0x7FFF downwards. We have loaded it
+		 ** at some other address. The startup code goes into the small
+		 ** ram window at Sram2, in the last 8 bytes, which are really
+		 ** at addresses 0x7FF8-0x7FFF.
+		 **
+		 ** If the loadbase is, say, 0x7C00, then we need to branch to
+		 ** address 0x7BFE to run the host.bin startup code. We assemble
+		 ** this jump manually.
+		 **
+		 ** The two byte sequence 60 08 is loaded into memory at address
+		 ** 0x7FFE,F. This is a local branch to location 0x7FF8 (60 is nfix 0,
+		 ** which adds '0' to the .O register, complements .O, and then shifts
+		 ** it left by 4 bit positions, 08 is a jump .O+8 instruction. This will
+		 ** add 8 to .O (which was 0xFFF0), and will branch RELATIVE to the new
+		 ** location. Now, the branch starts from the value of .PC (or .IP or
+		 ** whatever the bloody register is called on this chip), and the .PC
+		 ** will be pointing to the location AFTER the branch, in this case
+		 ** .PC == 0x8000, so the branch will be to 0x8000+0xFFF8 = 0x7FF8.
+		 **
+		 ** A long branch is coded at 0x7FF8. This consists of loading a four
+		 ** byte offset into .O using nfix (as above) and pfix operators. The
+		 ** pfix operates in exactly the same way as the nfix operator, but
+		 ** without the complement operation. The offset, of course, must be
+		 ** relative to the address of the byte AFTER the branch instruction,
+		 ** which will be (urm) 0x7FFC, so, our final destination of the branch
+		 ** (loadbase-2), has to be reached from here. Imagine that the loadbase
+		 ** is 0x7C00 (which it is), then we will need to branch to 0x7BFE (which
+		 ** is the first byte of the initial two byte short local branch of the
+		 ** download code).
+		 **
+		 ** To code a jump from 0x7FFC (which is where the branch will start
+		 ** from) to 0x7BFE, we will need to branch 0xFC02 bytes (0x7FFC+0xFC02)=
+		 ** 0x7BFE.
+		 ** This will be coded as four bytes:
+		 ** 60 2C 20 02
+		 ** being nfix .O+0
+		 **        pfix .O+C
+		 **        pfix .O+0
+		 **        jump .O+2
+		 **
+		 ** The nfix operator is used, so that the startup code will be
+		 ** compatible with the whole Tp family. (lies, damn lies, it'll never
+		 ** work in a month of Sundays).
+		 **
+		 ** The nfix nyble is the 1s complement of the nyble value you
+		 ** want to load - in this case we wanted 'F' so we nfix loaded '0'.
+		 */
+
+
+		/*
+		 ** Dest points to the top 8 bytes of Sram2. The Tp jumps
+		 ** to 0x7FFE at reset time, and starts executing. This is
+		 ** a short branch to 0x7FF8, where a long branch is coded.
+		 */
+
+		DestP = &Cad[0x7FF8];	/* <<<---- READ THE ABOVE COMMENTS */
+
+#define	NFIX(N)	(0x60 | (N))	/* .O  = (~(.O + N))<<4 */
+#define	PFIX(N)	(0x20 | (N))	/* .O  =   (.O + N)<<4  */
+#define	JUMP(N)	(0x00 | (N))	/* .PC =   .PC + .O      */
+
+		/*
+		 ** 0x7FFC is the address of the location following the last byte of
+		 ** the four byte jump instruction.
+		 ** READ THE ABOVE COMMENTS
+		 **
+		 ** offset is (TO-FROM) % MEMSIZE, but with compound buggering about.
+		 ** Memsize is 64K for this range of Tp, so offset is a short (unsigned,
+		 ** cos I don't understand 2's complement).
+		 */
+		offset = (p->RIOConf.HostLoadBase - 2) - 0x7FFC;
+
+		writeb(NFIX(((unsigned short) (~offset) >> (unsigned short) 12) & 0xF), DestP);
+		writeb(PFIX((offset >> 8) & 0xF), DestP + 1);
+		writeb(PFIX((offset >> 4) & 0xF), DestP + 2);
+		writeb(JUMP(offset & 0xF), DestP + 3);
+
+		writeb(NFIX(0), DestP + 6);
+		writeb(JUMP(8), DestP + 7);
+
+		rio_dprintk(RIO_DEBUG_BOOT, "host loadbase is 0x%x\n", p->RIOConf.HostLoadBase);
+		rio_dprintk(RIO_DEBUG_BOOT, "startup offset is 0x%x\n", offset);
+
+		/*
+		 ** Flag what is going on
+		 */
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_STARTUP;
+
+		/*
+		 ** Grab a copy of the current ParmMap pointer, so we
+		 ** can tell when it has changed.
+		 */
+		OldParmMap = readw(&HostP->__ParmMapR);
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Original parmmap is 0x%x\n", OldParmMap);
+
+		/*
+		 ** And start it running (I hope).
+		 ** As there is nothing dodgy or obscure about the
+		 ** above code, this is guaranteed to work every time.
+		 */
+		rio_dprintk(RIO_DEBUG_BOOT, "Host Type = 0x%x, Mode = 0x%x, IVec = 0x%x\n", HostP->Type, HostP->Mode, HostP->Ivec);
+
+		rio_start_card_running(HostP);
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Set control port\n");
+
+		/*
+		 ** Now, wait for upto five seconds for the Tp to setup the parmmap
+		 ** pointer:
+		 */
+		for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && (readw(&HostP->__ParmMapR) == OldParmMap); wait_count++) {
+			rio_dprintk(RIO_DEBUG_BOOT, "Checkout %d, 0x%x\n", wait_count, readw(&HostP->__ParmMapR));
+			mdelay(100);
+
+		}
+
+		/*
+		 ** If the parmmap pointer is unchanged, then the host code
+		 ** has crashed & burned in a really spectacular way
+		 */
+		if (readw(&HostP->__ParmMapR) == OldParmMap) {
+			rio_dprintk(RIO_DEBUG_BOOT, "parmmap 0x%x\n", readw(&HostP->__ParmMapR));
+			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail\n");
+			HostP->Flags &= ~RUN_STATE;
+			HostP->Flags |= RC_STUFFED;
+			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+			continue;
+		}
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Running 0x%x\n", readw(&HostP->__ParmMapR));
+
+		/*
+		 ** Well, the board thought it was OK, and setup its parmmap
+		 ** pointer. For the time being, we will pretend that this
+		 ** board is running, and check out what the error flag says.
+		 */
+
+		/*
+		 ** Grab a 32 bit pointer to the parmmap structure
+		 */
+		ParmMapP = (PARM_MAP __iomem *) RIO_PTR(Cad, readw(&HostP->__ParmMapR));
+		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
+		ParmMapP = (PARM_MAP __iomem *)(Cad + readw(&HostP->__ParmMapR));
+		rio_dprintk(RIO_DEBUG_BOOT, "ParmMapP : %p\n", ParmMapP);
+
+		/*
+		 ** The links entry should be 0xFFFF; we set it up
+		 ** with a mask to say how many PHBs to use, and
+		 ** which links to use.
+		 */
+		if (readw(&ParmMapP->links) != 0xFFFF) {
+			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
+			rio_dprintk(RIO_DEBUG_BOOT, "Links = 0x%x\n", readw(&ParmMapP->links));
+			HostP->Flags &= ~RUN_STATE;
+			HostP->Flags |= RC_STUFFED;
+			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+			continue;
+		}
+
+		writew(RIO_LINK_ENABLE, &ParmMapP->links);
+
+		/*
+		 ** now wait for the card to set all the parmmap->XXX stuff
+		 ** this is a wait of upto two seconds....
+		 */
+		rio_dprintk(RIO_DEBUG_BOOT, "Looking for init_done - %d ticks\n", p->RIOConf.StartupTime);
+		HostP->timeout_id = 0;
+		for (wait_count = 0; (wait_count < p->RIOConf.StartupTime) && !readw(&ParmMapP->init_done); wait_count++) {
+			rio_dprintk(RIO_DEBUG_BOOT, "Waiting for init_done\n");
+			mdelay(100);
+		}
+		rio_dprintk(RIO_DEBUG_BOOT, "OK! init_done!\n");
+
+		if (readw(&ParmMapP->error) != E_NO_ERROR || !readw(&ParmMapP->init_done)) {
+			rio_dprintk(RIO_DEBUG_BOOT, "RIO Mesg Run Fail %s\n", HostP->Name);
+			rio_dprintk(RIO_DEBUG_BOOT, "Timedout waiting for init_done\n");
+			HostP->Flags &= ~RUN_STATE;
+			HostP->Flags |= RC_STUFFED;
+			RIOHostReset( HostP->Type, HostP->CardP, HostP->Slot );
+			continue;
+		}
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Got init_done\n");
+
+		/*
+		 ** It runs! It runs!
+		 */
+		rio_dprintk(RIO_DEBUG_BOOT, "Host ID %x Running\n", HostP->UniqueNum);
+
+		/*
+		 ** set the time period between interrupts.
+		 */
+		writew(p->RIOConf.Timer, &ParmMapP->timer);
+
+		/*
+		 ** Translate all the 16 bit pointers in the __ParmMapR into
+		 ** 32 bit pointers for the driver in ioremap space.
+		 */
+		HostP->ParmMapP = ParmMapP;
+		HostP->PhbP = (struct PHB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_ptr));
+		HostP->RupP = (struct RUP __iomem *) RIO_PTR(Cad, readw(&ParmMapP->rups));
+		HostP->PhbNumP = (unsigned short __iomem *) RIO_PTR(Cad, readw(&ParmMapP->phb_num_ptr));
+		HostP->LinkStrP = (struct LPB __iomem *) RIO_PTR(Cad, readw(&ParmMapP->link_str_ptr));
+
+		/*
+		 ** point the UnixRups at the real Rups
+		 */
+		for (RupN = 0; RupN < MAX_RUP; RupN++) {
+			HostP->UnixRups[RupN].RupP = &HostP->RupP[RupN];
+			HostP->UnixRups[RupN].Id = RupN + 1;
+			HostP->UnixRups[RupN].BaseSysPort = NO_PORT;
+			spin_lock_init(&HostP->UnixRups[RupN].RupLock);
+		}
+
+		for (RupN = 0; RupN < LINKS_PER_UNIT; RupN++) {
+			HostP->UnixRups[RupN + MAX_RUP].RupP = &HostP->LinkStrP[RupN].rup;
+			HostP->UnixRups[RupN + MAX_RUP].Id = 0;
+			HostP->UnixRups[RupN + MAX_RUP].BaseSysPort = NO_PORT;
+			spin_lock_init(&HostP->UnixRups[RupN + MAX_RUP].RupLock);
+		}
+
+		/*
+		 ** point the PortP->Phbs at the real Phbs
+		 */
+		for (PortN = p->RIOFirstPortsMapped; PortN < p->RIOLastPortsMapped + PORTS_PER_RTA; PortN++) {
+			if (p->RIOPortp[PortN]->HostP == HostP) {
+				struct Port *PortP = p->RIOPortp[PortN];
+				struct PHB __iomem *PhbP;
+				/* int oldspl; */
+
+				if (!PortP->Mapped)
+					continue;
+
+				PhbP = &HostP->PhbP[PortP->HostPort];
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+				PortP->PhbP = PhbP;
+
+				PortP->TxAdd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_add));
+				PortP->TxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_start));
+				PortP->TxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->tx_end));
+				PortP->RxRemove = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_remove));
+				PortP->RxStart = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_start));
+				PortP->RxEnd = (u16 __iomem *) RIO_PTR(Cad, readw(&PhbP->rx_end));
+
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				/*
+				 ** point the UnixRup at the base SysPort
+				 */
+				if (!(PortN % PORTS_PER_RTA))
+					HostP->UnixRups[PortP->RupNum].BaseSysPort = PortN;
+			}
+		}
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Set the card running... \n");
+		/*
+		 ** last thing - show the world that everything is in place
+		 */
+		HostP->Flags &= ~RUN_STATE;
+		HostP->Flags |= RC_RUNNING;
+	}
+	/*
+	 ** MPX always uses a poller. This is actually patched into the system
+	 ** configuration and called directly from each clock tick.
+	 **
+	 */
+	p->RIOPolling = 1;
+
+	p->RIOSystemUp++;
+
+	rio_dprintk(RIO_DEBUG_BOOT, "Done everything %x\n", HostP->Ivec);
+	func_exit();
+	return 0;
+}
+
+
+
+/**
+ *	RIOBootRup		-	Boot an RTA
+ *	@p: rio we are working with
+ *	@Rup: Rup number
+ *	@HostP: host object
+ *	@PacketP: packet to use
+ *
+ *	If we have successfully processed this boot, then
+ *	return 1. If we havent, then return 0.
+ */
+
+int RIOBootRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem *PacketP)
+{
+	struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
+	struct PktCmd_M *PktReplyP;
+	struct CmdBlk *CmdBlkP;
+	unsigned int sequence;
+
+	/*
+	 ** If we haven't been told what to boot, we can't boot it.
+	 */
+	if (p->RIONumBootPkts == 0) {
+		rio_dprintk(RIO_DEBUG_BOOT, "No RTA code to download yet\n");
+		return 0;
+	}
+
+	/*
+	 ** Special case of boot completed - if we get one of these then we
+	 ** don't need a command block. For all other cases we do, so handle
+	 ** this first and then get a command block, then handle every other
+	 ** case, relinquishing the command block if disaster strikes!
+	 */
+	if ((readb(&PacketP->len) & PKT_CMD_BIT) && (readb(&PktCmdP->Command) == BOOT_COMPLETED))
+		return RIOBootComplete(p, HostP, Rup, PktCmdP);
+
+	/*
+	 ** Try to allocate a command block. This is in kernel space
+	 */
+	if (!(CmdBlkP = RIOGetCmdBlk())) {
+		rio_dprintk(RIO_DEBUG_BOOT, "No command blocks to boot RTA! come back later.\n");
+		return 0;
+	}
+
+	/*
+	 ** Fill in the default info on the command block
+	 */
+	CmdBlkP->Packet.dest_unit = Rup < (unsigned short) MAX_RUP ? Rup : 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit = 0;
+	CmdBlkP->Packet.src_port = BOOT_RUP;
+
+	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+	PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
+
+	/*
+	 ** process COMMANDS on the boot rup!
+	 */
+	if (readb(&PacketP->len) & PKT_CMD_BIT) {
+		/*
+		 ** We only expect one type of command - a BOOT_REQUEST!
+		 */
+		if (readb(&PktCmdP->Command) != BOOT_REQUEST) {
+			rio_dprintk(RIO_DEBUG_BOOT, "Unexpected command %d on BOOT RUP %d of host %Zd\n", readb(&PktCmdP->Command), Rup, HostP - p->RIOHosts);
+			RIOFreeCmdBlk(CmdBlkP);
+			return 1;
+		}
+
+		/*
+		 ** Build a Boot Sequence command block
+		 **
+		 ** We no longer need to use "Boot Mode", we'll always allow
+		 ** boot requests - the boot will not complete if the device
+		 ** appears in the bindings table.
+		 **
+		 ** We'll just (always) set the command field in packet reply
+		 ** to allow an attempted boot sequence :
+		 */
+		PktReplyP->Command = BOOT_SEQUENCE;
+
+		PktReplyP->BootSequence.NumPackets = p->RIONumBootPkts;
+		PktReplyP->BootSequence.LoadBase = p->RIOConf.RtaLoadBase;
+		PktReplyP->BootSequence.CodeSize = p->RIOBootCount;
+
+		CmdBlkP->Packet.len = BOOT_SEQUENCE_LEN | PKT_CMD_BIT;
+
+		memcpy((void *) &CmdBlkP->Packet.data[BOOT_SEQUENCE_LEN], "BOOT", 4);
+
+		rio_dprintk(RIO_DEBUG_BOOT, "Boot RTA on Host %Zd Rup %d - %d (0x%x) packets to 0x%x\n", HostP - p->RIOHosts, Rup, p->RIONumBootPkts, p->RIONumBootPkts, p->RIOConf.RtaLoadBase);
+
+		/*
+		 ** If this host is in slave mode, send the RTA an invalid boot
+		 ** sequence command block to force it to kill the boot. We wait
+		 ** for half a second before sending this packet to prevent the RTA
+		 ** attempting to boot too often. The master host should then grab
+		 ** the RTA and make it its own.
+		 */
+		p->RIOBooting++;
+		RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+		return 1;
+	}
+
+	/*
+	 ** It is a request for boot data.
+	 */
+	sequence = readw(&PktCmdP->Sequence);
+
+	rio_dprintk(RIO_DEBUG_BOOT, "Boot block %d on Host %Zd Rup%d\n", sequence, HostP - p->RIOHosts, Rup);
+
+	if (sequence >= p->RIONumBootPkts) {
+		rio_dprintk(RIO_DEBUG_BOOT, "Got a request for packet %d, max is %d\n", sequence, p->RIONumBootPkts);
+	}
+
+	PktReplyP->Sequence = sequence;
+	memcpy(PktReplyP->BootData, p->RIOBootPackets[p->RIONumBootPkts - sequence - 1], RTA_BOOT_DATA_SIZE);
+	CmdBlkP->Packet.len = PKT_MAX_DATA_LEN;
+	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+	return 1;
+}
+
+/**
+ *	RIOBootComplete		-	RTA boot is done
+ *	@p: RIO we are working with
+ *	@HostP: Host structure
+ *	@Rup: RUP being used
+ *	@PktCmdP: Packet command that was used
+ *
+ *	This function is called when an RTA been booted.
+ *	If booted by a host, HostP->HostUniqueNum is the booting host.
+ *	If booted by an RTA, HostP->Mapping[Rup].RtaUniqueNum is the booting RTA.
+ *	RtaUniq is the booted RTA.
+ */
+
+static int RIOBootComplete(struct rio_info *p, struct Host *HostP, unsigned int Rup, struct PktCmd __iomem *PktCmdP)
+{
+	struct Map *MapP = NULL;
+	struct Map *MapP2 = NULL;
+	int Flag;
+	int found;
+	int host, rta;
+	int EmptySlot = -1;
+	int entry, entry2;
+	char *MyType, *MyName;
+	unsigned int MyLink;
+	unsigned short RtaType;
+	u32 RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
+
+	p->RIOBooting = 0;
+
+	rio_dprintk(RIO_DEBUG_BOOT, "RTA Boot completed - BootInProgress now %d\n", p->RIOBooting);
+
+	/*
+	 ** Determine type of unit (16/8 port RTA).
+	 */
+
+	RtaType = GetUnitType(RtaUniq);
+	if (Rup >= (unsigned short) MAX_RUP)
+		rio_dprintk(RIO_DEBUG_BOOT, "RIO: Host %s has booted an RTA(%d) on link %c\n", HostP->Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
+	else
+		rio_dprintk(RIO_DEBUG_BOOT, "RIO: RTA %s has booted an RTA(%d) on link %c\n", HostP->Mapping[Rup].Name, 8 * RtaType, readb(&PktCmdP->LinkNum) + 'A');
+
+	rio_dprintk(RIO_DEBUG_BOOT, "UniqNum is 0x%x\n", RtaUniq);
+
+	if (RtaUniq == 0x00000000 || RtaUniq == 0xffffffff) {
+		rio_dprintk(RIO_DEBUG_BOOT, "Illegal RTA Uniq Number\n");
+		return 1;
+	}
+
+	/*
+	 ** If this RTA has just booted an RTA which doesn't belong to this
+	 ** system, or the system is in slave mode, do not attempt to create
+	 ** a new table entry for it.
+	 */
+
+	if (!RIOBootOk(p, HostP, RtaUniq)) {
+		MyLink = readb(&PktCmdP->LinkNum);
+		if (Rup < (unsigned short) MAX_RUP) {
+			/*
+			 ** RtaUniq was clone booted (by this RTA). Instruct this RTA
+			 ** to hold off further attempts to boot on this link for 30
+			 ** seconds.
+			 */
+			if (RIOSuspendBootRta(HostP, HostP->Mapping[Rup].ID, MyLink)) {
+				rio_dprintk(RIO_DEBUG_BOOT, "RTA failed to suspend booting on link %c\n", 'A' + MyLink);
+			}
+		} else
+			/*
+			 ** RtaUniq was booted by this host. Set the booting link
+			 ** to hold off for 30 seconds to give another unit a
+			 ** chance to boot it.
+			 */
+			writew(30, &HostP->LinkStrP[MyLink].WaitNoBoot);
+		rio_dprintk(RIO_DEBUG_BOOT, "RTA %x not owned - suspend booting down link %c on unit %x\n", RtaUniq, 'A' + MyLink, HostP->Mapping[Rup].RtaUniqueNum);
+		return 1;
+	}
+
+	/*
+	 ** Check for a SLOT_IN_USE entry for this RTA attached to the
+	 ** current host card in the driver table.
+	 **
+	 ** If it exists, make a note that we have booted it. Other parts of
+	 ** the driver are interested in this information at a later date,
+	 ** in particular when the booting RTA asks for an ID for this unit,
+	 ** we must have set the BOOTED flag, and the NEWBOOT flag is used
+	 ** to force an open on any ports that where previously open on this
+	 ** unit.
+	 */
+	for (entry = 0; entry < MAX_RUP; entry++) {
+		unsigned int sysport;
+
+		if ((HostP->Mapping[entry].Flags & SLOT_IN_USE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
+			HostP->Mapping[entry].Flags |= RTA_BOOTED | RTA_NEWBOOT;
+			if ((sysport = HostP->Mapping[entry].SysPort) != NO_PORT) {
+				if (sysport < p->RIOFirstPortsBooted)
+					p->RIOFirstPortsBooted = sysport;
+				if (sysport > p->RIOLastPortsBooted)
+					p->RIOLastPortsBooted = sysport;
+				/*
+				 ** For a 16 port RTA, check the second bank of 8 ports
+				 */
+				if (RtaType == TYPE_RTA16) {
+					entry2 = HostP->Mapping[entry].ID2 - 1;
+					HostP->Mapping[entry2].Flags |= RTA_BOOTED | RTA_NEWBOOT;
+					sysport = HostP->Mapping[entry2].SysPort;
+					if (sysport < p->RIOFirstPortsBooted)
+						p->RIOFirstPortsBooted = sysport;
+					if (sysport > p->RIOLastPortsBooted)
+						p->RIOLastPortsBooted = sysport;
+				}
+			}
+			if (RtaType == TYPE_RTA16)
+				rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given IDs %d+%d\n", entry + 1, entry2 + 1);
+			else
+				rio_dprintk(RIO_DEBUG_BOOT, "RTA will be given ID %d\n", entry + 1);
+			return 1;
+		}
+	}
+
+	rio_dprintk(RIO_DEBUG_BOOT, "RTA not configured for this host\n");
+
+	if (Rup >= (unsigned short) MAX_RUP) {
+		/*
+		 ** It was a host that did the booting
+		 */
+		MyType = "Host";
+		MyName = HostP->Name;
+	} else {
+		/*
+		 ** It was an RTA that did the booting
+		 */
+		MyType = "RTA";
+		MyName = HostP->Mapping[Rup].Name;
+	}
+	MyLink = readb(&PktCmdP->LinkNum);
+
+	/*
+	 ** There is no SLOT_IN_USE entry for this RTA attached to the current
+	 ** host card in the driver table.
+	 **
+	 ** Check for a SLOT_TENTATIVE entry for this RTA attached to the
+	 ** current host card in the driver table.
+	 **
+	 ** If we find one, then we re-use that slot.
+	 */
+	for (entry = 0; entry < MAX_RUP; entry++) {
+		if ((HostP->Mapping[entry].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry].RtaUniqueNum == RtaUniq)) {
+			if (RtaType == TYPE_RTA16) {
+				entry2 = HostP->Mapping[entry].ID2 - 1;
+				if ((HostP->Mapping[entry2].Flags & SLOT_TENTATIVE) && (HostP->Mapping[entry2].RtaUniqueNum == RtaUniq))
+					rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slots (%d+%d)\n", entry, entry2);
+				else
+					continue;
+			} else
+				rio_dprintk(RIO_DEBUG_BOOT, "Found previous tentative slot (%d)\n", entry);
+			if (!p->RIONoMessage)
+				printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
+			return 1;
+		}
+	}
+
+	/*
+	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	 ** attached to the current host card in the driver table.
+	 **
+	 ** Check if there is a SLOT_IN_USE or SLOT_TENTATIVE entry on another
+	 ** host for this RTA in the driver table.
+	 **
+	 ** For a SLOT_IN_USE entry on another host, we need to delete the RTA
+	 ** entry from the other host and add it to this host (using some of
+	 ** the functions from table.c which do this).
+	 ** For a SLOT_TENTATIVE entry on another host, we must cope with the
+	 ** following scenario:
+	 **
+	 ** + Plug 8 port RTA into host A. (This creates SLOT_TENTATIVE entry
+	 **   in table)
+	 ** + Unplug RTA and plug into host B. (We now have 2 SLOT_TENTATIVE
+	 **   entries)
+	 ** + Configure RTA on host B. (This slot now becomes SLOT_IN_USE)
+	 ** + Unplug RTA and plug back into host A.
+	 ** + Configure RTA on host A. We now have the same RTA configured
+	 **   with different ports on two different hosts.
+	 */
+	rio_dprintk(RIO_DEBUG_BOOT, "Have we seen RTA %x before?\n", RtaUniq);
+	found = 0;
+	Flag = 0;		/* Convince the compiler this variable is initialized */
+	for (host = 0; !found && (host < p->RIONumHosts); host++) {
+		for (rta = 0; rta < MAX_RUP; rta++) {
+			if ((p->RIOHosts[host].Mapping[rta].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (p->RIOHosts[host].Mapping[rta].RtaUniqueNum == RtaUniq)) {
+				Flag = p->RIOHosts[host].Mapping[rta].Flags;
+				MapP = &p->RIOHosts[host].Mapping[rta];
+				if (RtaType == TYPE_RTA16) {
+					MapP2 = &p->RIOHosts[host].Mapping[MapP->ID2 - 1];
+					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is units %d+%d from host %s\n", rta + 1, MapP->ID2, p->RIOHosts[host].Name);
+				} else
+					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is unit %d from host %s\n", rta + 1, p->RIOHosts[host].Name);
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	/*
+	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	 ** attached to the current host card in the driver table.
+	 **
+	 ** If we have not found a SLOT_IN_USE or SLOT_TENTATIVE entry on
+	 ** another host for this RTA in the driver table...
+	 **
+	 ** Check for a SLOT_IN_USE entry for this RTA in the config table.
+	 */
+	if (!MapP) {
+		rio_dprintk(RIO_DEBUG_BOOT, "Look for RTA %x in RIOSavedTable\n", RtaUniq);
+		for (rta = 0; rta < TOTAL_MAP_ENTRIES; rta++) {
+			rio_dprintk(RIO_DEBUG_BOOT, "Check table entry %d (%x)", rta, p->RIOSavedTable[rta].RtaUniqueNum);
+
+			if ((p->RIOSavedTable[rta].Flags & SLOT_IN_USE) && (p->RIOSavedTable[rta].RtaUniqueNum == RtaUniq)) {
+				MapP = &p->RIOSavedTable[rta];
+				Flag = p->RIOSavedTable[rta].Flags;
+				if (RtaType == TYPE_RTA16) {
+					for (entry2 = rta + 1; entry2 < TOTAL_MAP_ENTRIES; entry2++) {
+						if (p->RIOSavedTable[entry2].RtaUniqueNum == RtaUniq)
+							break;
+					}
+					MapP2 = &p->RIOSavedTable[entry2];
+					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entries %d+%d\n", rta, entry2);
+				} else
+					rio_dprintk(RIO_DEBUG_BOOT, "This RTA is from table entry %d\n", rta);
+				break;
+			}
+		}
+	}
+
+	/*
+	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	 ** attached to the current host card in the driver table.
+	 **
+	 ** We may have found a SLOT_IN_USE entry on another host for this
+	 ** RTA in the config table, or a SLOT_IN_USE or SLOT_TENTATIVE entry
+	 ** on another host for this RTA in the driver table.
+	 **
+	 ** Check the driver table for room to fit this newly discovered RTA.
+	 ** RIOFindFreeID() first looks for free slots and if it does not
+	 ** find any free slots it will then attempt to oust any
+	 ** tentative entry in the table.
+	 */
+	EmptySlot = 1;
+	if (RtaType == TYPE_RTA16) {
+		if (RIOFindFreeID(p, HostP, &entry, &entry2) == 0) {
+			RIODefaultName(p, HostP, entry);
+			rio_fill_host_slot(entry, entry2, RtaUniq, HostP);
+			EmptySlot = 0;
+		}
+	} else {
+		if (RIOFindFreeID(p, HostP, &entry, NULL) == 0) {
+			RIODefaultName(p, HostP, entry);
+			rio_fill_host_slot(entry, 0, RtaUniq, HostP);
+			EmptySlot = 0;
+		}
+	}
+
+	/*
+	 ** There is no SLOT_IN_USE or SLOT_TENTATIVE entry for this RTA
+	 ** attached to the current host card in the driver table.
+	 **
+	 ** If we found a SLOT_IN_USE entry on another host for this
+	 ** RTA in the config or driver table, and there are enough free
+	 ** slots in the driver table, then we need to move it over and
+	 ** delete it from the other host.
+	 ** If we found a SLOT_TENTATIVE entry on another host for this
+	 ** RTA in the driver table, just delete the other host entry.
+	 */
+	if (EmptySlot == 0) {
+		if (MapP) {
+			if (Flag & SLOT_IN_USE) {
+				rio_dprintk(RIO_DEBUG_BOOT, "This RTA configured on another host - move entry to current host (1)\n");
+				HostP->Mapping[entry].SysPort = MapP->SysPort;
+				memcpy(HostP->Mapping[entry].Name, MapP->Name, MAX_NAME_LEN);
+				HostP->Mapping[entry].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT;
+				RIOReMapPorts(p, HostP, &HostP->Mapping[entry]);
+				if (HostP->Mapping[entry].SysPort < p->RIOFirstPortsBooted)
+					p->RIOFirstPortsBooted = HostP->Mapping[entry].SysPort;
+				if (HostP->Mapping[entry].SysPort > p->RIOLastPortsBooted)
+					p->RIOLastPortsBooted = HostP->Mapping[entry].SysPort;
+				rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) MapP->SysPort, MapP->Name);
+			} else {
+				rio_dprintk(RIO_DEBUG_BOOT, "This RTA has a tentative entry on another host - delete that entry (1)\n");
+				HostP->Mapping[entry].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT;
+			}
+			if (RtaType == TYPE_RTA16) {
+				if (Flag & SLOT_IN_USE) {
+					HostP->Mapping[entry2].Flags = SLOT_IN_USE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+					HostP->Mapping[entry2].SysPort = MapP2->SysPort;
+					/*
+					 ** Map second block of ttys for 16 port RTA
+					 */
+					RIOReMapPorts(p, HostP, &HostP->Mapping[entry2]);
+					if (HostP->Mapping[entry2].SysPort < p->RIOFirstPortsBooted)
+						p->RIOFirstPortsBooted = HostP->Mapping[entry2].SysPort;
+					if (HostP->Mapping[entry2].SysPort > p->RIOLastPortsBooted)
+						p->RIOLastPortsBooted = HostP->Mapping[entry2].SysPort;
+					rio_dprintk(RIO_DEBUG_BOOT, "SysPort %d, Name %s\n", (int) HostP->Mapping[entry2].SysPort, HostP->Mapping[entry].Name);
+				} else
+					HostP->Mapping[entry2].Flags = SLOT_TENTATIVE | RTA_BOOTED | RTA_NEWBOOT | RTA16_SECOND_SLOT;
+				memset(MapP2, 0, sizeof(struct Map));
+			}
+			memset(MapP, 0, sizeof(struct Map));
+			if (!p->RIONoMessage)
+				printk("An orphaned RTA has been adopted by %s '%s' (%c).\n", MyType, MyName, MyLink + 'A');
+		} else if (!p->RIONoMessage)
+			printk("RTA connected to %s '%s' (%c) not configured.\n", MyType, MyName, MyLink + 'A');
+		RIOSetChange(p);
+		return 1;
+	}
+
+	/*
+	 ** There is no room in the driver table to make an entry for the
+	 ** booted RTA. Keep a note of its Uniq Num in the overflow table,
+	 ** so we can ignore it's ID requests.
+	 */
+	if (!p->RIONoMessage)
+		printk("The RTA connected to %s '%s' (%c) cannot be configured.  You cannot configure more than 128 ports to one host card.\n", MyType, MyName, MyLink + 'A');
+	for (entry = 0; entry < HostP->NumExtraBooted; entry++) {
+		if (HostP->ExtraUnits[entry] == RtaUniq) {
+			/*
+			 ** already got it!
+			 */
+			return 1;
+		}
+	}
+	/*
+	 ** If there is room, add the unit to the list of extras
+	 */
+	if (HostP->NumExtraBooted < MAX_EXTRA_UNITS)
+		HostP->ExtraUnits[HostP->NumExtraBooted++] = RtaUniq;
+	return 1;
+}
+
+
+/*
+** If the RTA or its host appears in the RIOBindTab[] structure then
+** we mustn't boot the RTA and should return 0.
+** This operation is slightly different from the other drivers for RIO
+** in that this is designed to work with the new utilities
+** not config.rio and is FAR SIMPLER.
+** We no longer support the RIOBootMode variable. It is all done from the
+** "boot/noboot" field in the rio.cf file.
+*/
+int RIOBootOk(struct rio_info *p, struct Host *HostP, unsigned long RtaUniq)
+{
+	int Entry;
+	unsigned int HostUniq = HostP->UniqueNum;
+
+	/*
+	 ** Search bindings table for RTA or its parent.
+	 ** If it exists, return 0, else 1.
+	 */
+	for (Entry = 0; (Entry < MAX_RTA_BINDINGS) && (p->RIOBindTab[Entry] != 0); Entry++) {
+		if ((p->RIOBindTab[Entry] == HostUniq) || (p->RIOBindTab[Entry] == RtaUniq))
+			return 0;
+	}
+	return 1;
+}
+
+/*
+** Make an empty slot tentative. If this is a 16 port RTA, make both
+** slots tentative, and the second one RTA_SECOND_SLOT as well.
+*/
+
+void rio_fill_host_slot(int entry, int entry2, unsigned int rta_uniq, struct Host *host)
+{
+	int link;
+
+	rio_dprintk(RIO_DEBUG_BOOT, "rio_fill_host_slot(%d, %d, 0x%x...)\n", entry, entry2, rta_uniq);
+
+	host->Mapping[entry].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE);
+	host->Mapping[entry].SysPort = NO_PORT;
+	host->Mapping[entry].RtaUniqueNum = rta_uniq;
+	host->Mapping[entry].HostUniqueNum = host->UniqueNum;
+	host->Mapping[entry].ID = entry + 1;
+	host->Mapping[entry].ID2 = 0;
+	if (entry2) {
+		host->Mapping[entry2].Flags = (RTA_BOOTED | RTA_NEWBOOT | SLOT_TENTATIVE | RTA16_SECOND_SLOT);
+		host->Mapping[entry2].SysPort = NO_PORT;
+		host->Mapping[entry2].RtaUniqueNum = rta_uniq;
+		host->Mapping[entry2].HostUniqueNum = host->UniqueNum;
+		host->Mapping[entry2].Name[0] = '\0';
+		host->Mapping[entry2].ID = entry2 + 1;
+		host->Mapping[entry2].ID2 = entry + 1;
+		host->Mapping[entry].ID2 = entry2 + 1;
+	}
+	/*
+	 ** Must set these up, so that utilities show
+	 ** topology of 16 port RTAs correctly
+	 */
+	for (link = 0; link < LINKS_PER_UNIT; link++) {
+		host->Mapping[entry].Topology[link].Unit = ROUTE_DISCONNECT;
+		host->Mapping[entry].Topology[link].Link = NO_LINK;
+		if (entry2) {
+			host->Mapping[entry2].Topology[link].Unit = ROUTE_DISCONNECT;
+			host->Mapping[entry2].Topology[link].Link = NO_LINK;
+		}
+	}
+}
diff --git a/drivers/staging/generic_serial/rio/riocmd.c b/drivers/staging/generic_serial/rio/riocmd.c
new file mode 100644
index 0000000..f121357
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riocmd.c
@@ -0,0 +1,939 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  ported from the existing SCO driver source
+**
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riocmd.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:41
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riocmd.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+
+
+static struct IdentifyRta IdRta;
+static struct KillNeighbour KillUnit;
+
+int RIOFoadRta(struct Host *HostP, struct Map *MapP)
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA\n");
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if (!CmdBlkP) {
+		rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA: GetCmdBlk failed\n");
+		return -ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit = 0;
+	CmdBlkP->Packet.src_port = BOOT_RUP;
+	CmdBlkP->Packet.len = 0x84;
+	CmdBlkP->Packet.data[0] = IFOAD;
+	CmdBlkP->Packet.data[1] = 0;
+	CmdBlkP->Packet.data[2] = IFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3] = (IFOAD_MAGIC >> 8) & 0xFF;
+
+	if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+		rio_dprintk(RIO_DEBUG_CMD, "FOAD RTA: Failed to queue foad command\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int RIOZombieRta(struct Host *HostP, struct Map *MapP)
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA\n");
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if (!CmdBlkP) {
+		rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA: GetCmdBlk failed\n");
+		return -ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = MapP->ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit = 0;
+	CmdBlkP->Packet.src_port = BOOT_RUP;
+	CmdBlkP->Packet.len = 0x84;
+	CmdBlkP->Packet.data[0] = ZOMBIE;
+	CmdBlkP->Packet.data[1] = 0;
+	CmdBlkP->Packet.data[2] = ZOMBIE_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3] = (ZOMBIE_MAGIC >> 8) & 0xFF;
+
+	if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+		rio_dprintk(RIO_DEBUG_CMD, "ZOMBIE RTA: Failed to queue zombie command\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int RIOCommandRta(struct rio_info *p, unsigned long RtaUnique, int (*func) (struct Host * HostP, struct Map * MapP))
+{
+	unsigned int Host;
+
+	rio_dprintk(RIO_DEBUG_CMD, "Command RTA 0x%lx func %p\n", RtaUnique, func);
+
+	if (!RtaUnique)
+		return (0);
+
+	for (Host = 0; Host < p->RIONumHosts; Host++) {
+		unsigned int Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for (Rta = 0; Rta < RTAS_PER_HOST; Rta++) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if (MapP->RtaUniqueNum == RtaUnique) {
+				uint Link;
+
+				/*
+				 ** now, lets just check we have a route to it...
+				 ** IF the routing stuff is working, then one of the
+				 ** topology entries for this unit will have a legit
+				 ** route *somewhere*. We care not where - if its got
+				 ** any connections, we can get to it.
+				 */
+				for (Link = 0; Link < LINKS_PER_UNIT; Link++) {
+					if (MapP->Topology[Link].Unit <= (u8) MAX_RUP) {
+						/*
+						 ** Its worth trying the operation...
+						 */
+						return (*func) (HostP, MapP);
+					}
+				}
+			}
+		}
+	}
+	return -ENXIO;
+}
+
+
+int RIOIdentifyRta(struct rio_info *p, void __user * arg)
+{
+	unsigned int Host;
+
+	if (copy_from_user(&IdRta, arg, sizeof(IdRta))) {
+		rio_dprintk(RIO_DEBUG_CMD, "RIO_IDENTIFY_RTA copy failed\n");
+		p->RIOError.Error = COPYIN_FAILED;
+		return -EFAULT;
+	}
+
+	for (Host = 0; Host < p->RIONumHosts; Host++) {
+		unsigned int Rta;
+		struct Host *HostP = &p->RIOHosts[Host];
+
+		for (Rta = 0; Rta < RTAS_PER_HOST; Rta++) {
+			struct Map *MapP = &HostP->Mapping[Rta];
+
+			if (MapP->RtaUniqueNum == IdRta.RtaUnique) {
+				uint Link;
+				/*
+				 ** now, lets just check we have a route to it...
+				 ** IF the routing stuff is working, then one of the
+				 ** topology entries for this unit will have a legit
+				 ** route *somewhere*. We care not where - if its got
+				 ** any connections, we can get to it.
+				 */
+				for (Link = 0; Link < LINKS_PER_UNIT; Link++) {
+					if (MapP->Topology[Link].Unit <= (u8) MAX_RUP) {
+						/*
+						 ** Its worth trying the operation...
+						 */
+						struct CmdBlk *CmdBlkP;
+
+						rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA\n");
+
+						CmdBlkP = RIOGetCmdBlk();
+
+						if (!CmdBlkP) {
+							rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA: GetCmdBlk failed\n");
+							return -ENXIO;
+						}
+
+						CmdBlkP->Packet.dest_unit = MapP->ID;
+						CmdBlkP->Packet.dest_port = BOOT_RUP;
+						CmdBlkP->Packet.src_unit = 0;
+						CmdBlkP->Packet.src_port = BOOT_RUP;
+						CmdBlkP->Packet.len = 0x84;
+						CmdBlkP->Packet.data[0] = IDENTIFY;
+						CmdBlkP->Packet.data[1] = 0;
+						CmdBlkP->Packet.data[2] = IdRta.ID;
+
+						if (RIOQueueCmdBlk(HostP, MapP->ID - 1, CmdBlkP) == RIO_FAIL) {
+							rio_dprintk(RIO_DEBUG_CMD, "IDENTIFY RTA: Failed to queue command\n");
+							return -EIO;
+						}
+						return 0;
+					}
+				}
+			}
+		}
+	}
+	return -ENOENT;
+}
+
+
+int RIOKillNeighbour(struct rio_info *p, void __user * arg)
+{
+	uint Host;
+	uint ID;
+	struct Host *HostP;
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprintk(RIO_DEBUG_CMD, "KILL HOST NEIGHBOUR\n");
+
+	if (copy_from_user(&KillUnit, arg, sizeof(KillUnit))) {
+		rio_dprintk(RIO_DEBUG_CMD, "RIO_KILL_NEIGHBOUR copy failed\n");
+		p->RIOError.Error = COPYIN_FAILED;
+		return -EFAULT;
+	}
+
+	if (KillUnit.Link > 3)
+		return -ENXIO;
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if (!CmdBlkP) {
+		rio_dprintk(RIO_DEBUG_CMD, "UFOAD: GetCmdBlk failed\n");
+		return -ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = 0;
+	CmdBlkP->Packet.src_unit = 0;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_port = BOOT_RUP;
+	CmdBlkP->Packet.len = 0x84;
+	CmdBlkP->Packet.data[0] = UFOAD;
+	CmdBlkP->Packet.data[1] = KillUnit.Link;
+	CmdBlkP->Packet.data[2] = UFOAD_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3] = (UFOAD_MAGIC >> 8) & 0xFF;
+
+	for (Host = 0; Host < p->RIONumHosts; Host++) {
+		ID = 0;
+		HostP = &p->RIOHosts[Host];
+
+		if (HostP->UniqueNum == KillUnit.UniqueNum) {
+			if (RIOQueueCmdBlk(HostP, RTAS_PER_HOST + KillUnit.Link, CmdBlkP) == RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_CMD, "UFOAD: Failed queue command\n");
+				return -EIO;
+			}
+			return 0;
+		}
+
+		for (ID = 0; ID < RTAS_PER_HOST; ID++) {
+			if (HostP->Mapping[ID].RtaUniqueNum == KillUnit.UniqueNum) {
+				CmdBlkP->Packet.dest_unit = ID + 1;
+				if (RIOQueueCmdBlk(HostP, ID, CmdBlkP) == RIO_FAIL) {
+					rio_dprintk(RIO_DEBUG_CMD, "UFOAD: Failed queue command\n");
+					return -EIO;
+				}
+				return 0;
+			}
+		}
+	}
+	RIOFreeCmdBlk(CmdBlkP);
+	return -ENXIO;
+}
+
+int RIOSuspendBootRta(struct Host *HostP, int ID, int Link)
+{
+	struct CmdBlk *CmdBlkP;
+
+	rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA ID %d, link %c\n", ID, 'A' + Link);
+
+	CmdBlkP = RIOGetCmdBlk();
+
+	if (!CmdBlkP) {
+		rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: GetCmdBlk failed\n");
+		return -ENXIO;
+	}
+
+	CmdBlkP->Packet.dest_unit = ID;
+	CmdBlkP->Packet.dest_port = BOOT_RUP;
+	CmdBlkP->Packet.src_unit = 0;
+	CmdBlkP->Packet.src_port = BOOT_RUP;
+	CmdBlkP->Packet.len = 0x84;
+	CmdBlkP->Packet.data[0] = IWAIT;
+	CmdBlkP->Packet.data[1] = Link;
+	CmdBlkP->Packet.data[2] = IWAIT_MAGIC & 0xFF;
+	CmdBlkP->Packet.data[3] = (IWAIT_MAGIC >> 8) & 0xFF;
+
+	if (RIOQueueCmdBlk(HostP, ID - 1, CmdBlkP) == RIO_FAIL) {
+		rio_dprintk(RIO_DEBUG_CMD, "SUSPEND BOOT ON RTA: Failed to queue iwait command\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+int RIOFoadWakeup(struct rio_info *p)
+{
+	int port;
+	struct Port *PortP;
+	unsigned long flags;
+
+	for (port = 0; port < RIO_PORTS; port++) {
+		PortP = p->RIOPortp[port];
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->Config = 0;
+		PortP->State = 0;
+		PortP->InUse = NOT_INUSE;
+		PortP->PortState = 0;
+		PortP->FlushCmdBodge = 0;
+		PortP->ModemLines = 0;
+		PortP->ModemState = 0;
+		PortP->CookMode = 0;
+		PortP->ParamSem = 0;
+		PortP->Mapped = 0;
+		PortP->WflushFlag = 0;
+		PortP->MagicFlags = 0;
+		PortP->RxDataStart = 0;
+		PortP->TxBufferIn = 0;
+		PortP->TxBufferOut = 0;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	return (0);
+}
+
+/*
+** Incoming command on the COMMAND_RUP to be processed.
+*/
+static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struct PKT __iomem *PacketP)
+{
+	struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *)PacketP->data;
+	struct Port *PortP;
+	struct UnixRup *UnixRupP;
+	unsigned short SysPort;
+	unsigned short ReportedModemStatus;
+	unsigned short rup;
+	unsigned short subCommand;
+	unsigned long flags;
+
+	func_enter();
+
+	/*
+	 ** 16 port RTA note:
+	 ** Command rup packets coming from the RTA will have pkt->data[1] (which
+	 ** translates to PktCmdP->PhbNum) set to the host port number for the
+	 ** particular unit. To access the correct BaseSysPort for a 16 port RTA,
+	 ** we can use PhbNum to get the rup number for the appropriate 8 port
+	 ** block (for the first block, this should be equal to 'Rup').
+	 */
+	rup = readb(&PktCmdP->PhbNum) / (unsigned short) PORTS_PER_RTA;
+	UnixRupP = &HostP->UnixRups[rup];
+	SysPort = UnixRupP->BaseSysPort + (readb(&PktCmdP->PhbNum) % (unsigned short) PORTS_PER_RTA);
+	rio_dprintk(RIO_DEBUG_CMD, "Command on rup %d, port %d\n", rup, SysPort);
+
+	if (UnixRupP->BaseSysPort == NO_PORT) {
+		rio_dprintk(RIO_DEBUG_CMD, "OBSCURE ERROR!\n");
+		rio_dprintk(RIO_DEBUG_CMD, "Diagnostics follow. Please WRITE THESE DOWN and report them to Specialix Technical Support\n");
+		rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Host number %Zd, name ``%s''\n", HostP - p->RIOHosts, HostP->Name);
+		rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: Rup number  0x%x\n", rup);
+
+		if (Rup < (unsigned short) MAX_RUP) {
+			rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for RTA ``%s''\n", HostP->Mapping[Rup].Name);
+		} else
+			rio_dprintk(RIO_DEBUG_CMD, "CONTROL information: This is the RUP for link ``%c'' of host ``%s''\n", ('A' + Rup - MAX_RUP), HostP->Name);
+
+		rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Destination 0x%x:0x%x\n", readb(&PacketP->dest_unit), readb(&PacketP->dest_port));
+		rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Source	  0x%x:0x%x\n", readb(&PacketP->src_unit), readb(&PacketP->src_port));
+		rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Length	  0x%x (%d)\n", readb(&PacketP->len), readb(&PacketP->len));
+		rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Control	 0x%x (%d)\n", readb(&PacketP->control), readb(&PacketP->control));
+		rio_dprintk(RIO_DEBUG_CMD, "PACKET information: Check	   0x%x (%d)\n", readw(&PacketP->csum), readw(&PacketP->csum));
+		rio_dprintk(RIO_DEBUG_CMD, "COMMAND information: Host Port Number 0x%x, " "Command Code 0x%x\n", readb(&PktCmdP->PhbNum), readb(&PktCmdP->Command));
+		return 1;
+	}
+	PortP = p->RIOPortp[SysPort];
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	switch (readb(&PktCmdP->Command)) {
+	case RIOC_BREAK_RECEIVED:
+		rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n");
+		/* If the current line disc. is not multi-threading and
+		   the current processor is not the default, reset rup_intr
+		   and return 0 to ensure that the command packet is
+		   not freed. */
+		/* Call tmgr HANGUP HERE */
+		/* Fix this later when every thing works !!!! RAMRAJ */
+		gs_got_break(&PortP->gs);
+		break;
+
+	case RIOC_COMPLETE:
+		rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts);
+		subCommand = 1;
+		switch (readb(&PktCmdP->SubCommand)) {
+		case RIOC_MEMDUMP:
+			rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr));
+			break;
+		case RIOC_READ_REGISTER:
+			rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr));
+			p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST);
+			break;
+		default:
+			subCommand = 0;
+			break;
+		}
+		if (subCommand)
+			break;
+		rio_dprintk(RIO_DEBUG_CMD, "New status is 0x%x was 0x%x\n", readb(&PktCmdP->PortStatus), PortP->PortState);
+		if (PortP->PortState != readb(&PktCmdP->PortStatus)) {
+			rio_dprintk(RIO_DEBUG_CMD, "Mark status & wakeup\n");
+			PortP->PortState = readb(&PktCmdP->PortStatus);
+			/* What should we do here ...
+			   wakeup( &PortP->PortState );
+			 */
+		} else
+			rio_dprintk(RIO_DEBUG_CMD, "No change\n");
+
+		/* FALLTHROUGH */
+	case RIOC_MODEM_STATUS:
+		/*
+		 ** Knock out the tbusy and tstop bits, as these are not relevant
+		 ** to the check for modem status change (they're just there because
+		 ** it's a convenient place to put them!).
+		 */
+		ReportedModemStatus = readb(&PktCmdP->ModemStatus);
+		if ((PortP->ModemState & RIOC_MSVR1_HOST) ==
+				(ReportedModemStatus & RIOC_MSVR1_HOST)) {
+			rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState);
+			/*
+			 ** Update ModemState just in case tbusy or tstop states have
+			 ** changed.
+			 */
+			PortP->ModemState = ReportedModemStatus;
+		} else {
+			rio_dprintk(RIO_DEBUG_CMD, "Modem status change from 0x%x to 0x%x\n", PortP->ModemState, ReportedModemStatus);
+			PortP->ModemState = ReportedModemStatus;
+#ifdef MODEM_SUPPORT
+			if (PortP->Mapped) {
+				/***********************************************************\
+				*************************************************************
+				***													   ***
+				***		  M O D E M   S T A T E   C H A N G E		  ***
+				***													   ***
+				*************************************************************
+				\***********************************************************/
+				/*
+				 ** If the device is a modem, then check the modem
+				 ** carrier.
+				 */
+				if (PortP->gs.port.tty == NULL)
+					break;
+				if (PortP->gs.port.tty->termios == NULL)
+					break;
+
+				if (!(PortP->gs.port.tty->termios->c_cflag & CLOCAL) && ((PortP->State & (RIO_MOPEN | RIO_WOPEN)))) {
+
+					rio_dprintk(RIO_DEBUG_CMD, "Is there a Carrier?\n");
+					/*
+					 ** Is there a carrier?
+					 */
+					if (PortP->ModemState & RIOC_MSVR1_CD) {
+						/*
+						 ** Has carrier just appeared?
+						 */
+						if (!(PortP->State & RIO_CARR_ON)) {
+							rio_dprintk(RIO_DEBUG_CMD, "Carrier just came up.\n");
+							PortP->State |= RIO_CARR_ON;
+							/*
+							 ** wakeup anyone in WOPEN
+							 */
+							if (PortP->State & (PORT_ISOPEN | RIO_WOPEN))
+								wake_up_interruptible(&PortP->gs.port.open_wait);
+						}
+					} else {
+						/*
+						 ** Has carrier just dropped?
+						 */
+						if (PortP->State & RIO_CARR_ON) {
+							if (PortP->State & (PORT_ISOPEN | RIO_WOPEN | RIO_MOPEN))
+								tty_hangup(PortP->gs.port.tty);
+							PortP->State &= ~RIO_CARR_ON;
+							rio_dprintk(RIO_DEBUG_CMD, "Carrirer just went down\n");
+						}
+					}
+				}
+			}
+#endif
+		}
+		break;
+
+	default:
+		rio_dprintk(RIO_DEBUG_CMD, "Unknown command %d on CMD_RUP of host %Zd\n", readb(&PktCmdP->Command), HostP - p->RIOHosts);
+		break;
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	func_exit();
+
+	return 1;
+}
+
+/*
+** The command mechanism:
+**	Each rup has a chain of commands associated with it.
+**	This chain is maintained by routines in this file.
+**	Periodically we are called and we run a quick check of all the
+**	active chains to determine if there is a command to be executed,
+**	and if the rup is ready to accept it.
+**
+*/
+
+/*
+** Allocate an empty command block.
+*/
+struct CmdBlk *RIOGetCmdBlk(void)
+{
+	struct CmdBlk *CmdBlkP;
+
+	CmdBlkP = kzalloc(sizeof(struct CmdBlk), GFP_ATOMIC);
+	return CmdBlkP;
+}
+
+/*
+** Return a block to the head of the free list.
+*/
+void RIOFreeCmdBlk(struct CmdBlk *CmdBlkP)
+{
+	kfree(CmdBlkP);
+}
+
+/*
+** attach a command block to the list of commands to be performed for
+** a given rup.
+*/
+int RIOQueueCmdBlk(struct Host *HostP, uint Rup, struct CmdBlk *CmdBlkP)
+{
+	struct CmdBlk **Base;
+	struct UnixRup *UnixRupP;
+	unsigned long flags;
+
+	if (Rup >= (unsigned short) (MAX_RUP + LINKS_PER_UNIT)) {
+		rio_dprintk(RIO_DEBUG_CMD, "Illegal rup number %d in RIOQueueCmdBlk\n", Rup);
+		RIOFreeCmdBlk(CmdBlkP);
+		return RIO_FAIL;
+	}
+
+	UnixRupP = &HostP->UnixRups[Rup];
+
+	rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+	/*
+	 ** If the RUP is currently inactive, then put the request
+	 ** straight on the RUP....
+	 */
+	if ((UnixRupP->CmdsWaitingP == NULL) && (UnixRupP->CmdPendingP == NULL) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE) && (CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP)
+																	     : 1)) {
+		rio_dprintk(RIO_DEBUG_CMD, "RUP inactive-placing command straight on. Cmd byte is 0x%x\n", CmdBlkP->Packet.data[0]);
+
+		/*
+		 ** Whammy! blat that pack!
+		 */
+		HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct PKT));
+
+		/*
+		 ** place command packet on the pending position.
+		 */
+		UnixRupP->CmdPendingP = CmdBlkP;
+
+		/*
+		 ** set the command register
+		 */
+		writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol);
+
+		rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+		return 0;
+	}
+	rio_dprintk(RIO_DEBUG_CMD, "RUP active - en-queing\n");
+
+	if (UnixRupP->CmdsWaitingP != NULL)
+		rio_dprintk(RIO_DEBUG_CMD, "Rup active - command waiting\n");
+	if (UnixRupP->CmdPendingP != NULL)
+		rio_dprintk(RIO_DEBUG_CMD, "Rup active - command pending\n");
+	if (readw(&UnixRupP->RupP->txcontrol) != TX_RUP_INACTIVE)
+		rio_dprintk(RIO_DEBUG_CMD, "Rup active - command rup not ready\n");
+
+	Base = &UnixRupP->CmdsWaitingP;
+
+	rio_dprintk(RIO_DEBUG_CMD, "First try to queue cmdblk %p at %p\n", CmdBlkP, Base);
+
+	while (*Base) {
+		rio_dprintk(RIO_DEBUG_CMD, "Command cmdblk %p here\n", *Base);
+		Base = &((*Base)->NextP);
+		rio_dprintk(RIO_DEBUG_CMD, "Now try to queue cmd cmdblk %p at %p\n", CmdBlkP, Base);
+	}
+
+	rio_dprintk(RIO_DEBUG_CMD, "Will queue cmdblk %p at %p\n", CmdBlkP, Base);
+
+	*Base = CmdBlkP;
+
+	CmdBlkP->NextP = NULL;
+
+	rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+
+	return 0;
+}
+
+/*
+** Here we go - if there is an empty rup, fill it!
+** must be called at splrio() or higher.
+*/
+void RIOPollHostCommands(struct rio_info *p, struct Host *HostP)
+{
+	struct CmdBlk *CmdBlkP;
+	struct UnixRup *UnixRupP;
+	struct PKT __iomem *PacketP;
+	unsigned short Rup;
+	unsigned long flags;
+
+
+	Rup = MAX_RUP + LINKS_PER_UNIT;
+
+	do {			/* do this loop for each RUP */
+		/*
+		 ** locate the rup we are processing & lock it
+		 */
+		UnixRupP = &HostP->UnixRups[--Rup];
+
+		spin_lock_irqsave(&UnixRupP->RupLock, flags);
+
+		/*
+		 ** First check for incoming commands:
+		 */
+		if (readw(&UnixRupP->RupP->rxcontrol) != RX_RUP_INACTIVE) {
+			int FreeMe;
+
+			PacketP = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->rxpkt));
+
+			switch (readb(&PacketP->dest_port)) {
+			case BOOT_RUP:
+				rio_dprintk(RIO_DEBUG_CMD, "Incoming Boot %s packet '%x'\n", readb(&PacketP->len) & 0x80 ? "Command" : "Data", readb(&PacketP->data[0]));
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				FreeMe = RIOBootRup(p, Rup, HostP, PacketP);
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+				break;
+
+			case COMMAND_RUP:
+				/*
+				 ** Free the RUP lock as loss of carrier causes a
+				 ** ttyflush which will (eventually) call another
+				 ** routine that uses the RUP lock.
+				 */
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				FreeMe = RIOCommandRup(p, Rup, HostP, PacketP);
+				if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) {
+					rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6])));
+					rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32);
+				}
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+				break;
+
+			case ROUTE_RUP:
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				FreeMe = RIORouteRup(p, Rup, HostP, PacketP);
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+				break;
+
+			default:
+				rio_dprintk(RIO_DEBUG_CMD, "Unknown RUP %d\n", readb(&PacketP->dest_port));
+				FreeMe = 1;
+				break;
+			}
+
+			if (FreeMe) {
+				rio_dprintk(RIO_DEBUG_CMD, "Free processed incoming command packet\n");
+				put_free_end(HostP, PacketP);
+
+				writew(RX_RUP_INACTIVE, &UnixRupP->RupP->rxcontrol);
+
+				if (readw(&UnixRupP->RupP->handshake) == PHB_HANDSHAKE_SET) {
+					rio_dprintk(RIO_DEBUG_CMD, "Handshake rup %d\n", Rup);
+					writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &UnixRupP->RupP->handshake);
+				}
+			}
+		}
+
+		/*
+		 ** IF a command was running on the port,
+		 ** and it has completed, then tidy it up.
+		 */
+		if ((CmdBlkP = UnixRupP->CmdPendingP) &&	/* ASSIGN! */
+		    (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) {
+			/*
+			 ** we are idle.
+			 ** there is a command in pending.
+			 ** Therefore, this command has finished.
+			 ** So, wakeup whoever is waiting for it (and tell them
+			 ** what happened).
+			 */
+			if (CmdBlkP->Packet.dest_port == BOOT_RUP)
+				rio_dprintk(RIO_DEBUG_CMD, "Free Boot %s Command Block '%x'\n", CmdBlkP->Packet.len & 0x80 ? "Command" : "Data", CmdBlkP->Packet.data[0]);
+
+			rio_dprintk(RIO_DEBUG_CMD, "Command %p completed\n", CmdBlkP);
+
+			/*
+			 ** Clear the Rup lock to prevent mutual exclusion.
+			 */
+			if (CmdBlkP->PostFuncP) {
+				rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+				(*CmdBlkP->PostFuncP) (CmdBlkP->PostArg, CmdBlkP);
+				rio_spin_lock_irqsave(&UnixRupP->RupLock, flags);
+			}
+
+			/*
+			 ** ....clear the pending flag....
+			 */
+			UnixRupP->CmdPendingP = NULL;
+
+			/*
+			 ** ....and return the command block to the freelist.
+			 */
+			RIOFreeCmdBlk(CmdBlkP);
+		}
+
+		/*
+		 ** If there is a command for this rup, and the rup
+		 ** is idle, then process the command
+		 */
+		if ((CmdBlkP = UnixRupP->CmdsWaitingP) &&	/* ASSIGN! */
+		    (UnixRupP->CmdPendingP == NULL) && (readw(&UnixRupP->RupP->txcontrol) == TX_RUP_INACTIVE)) {
+			/*
+			 ** if the pre-function is non-zero, call it.
+			 ** If it returns RIO_FAIL then don't
+			 ** send this command yet!
+			 */
+			if (!(CmdBlkP->PreFuncP ? (*CmdBlkP->PreFuncP) (CmdBlkP->PreArg, CmdBlkP) : 1)) {
+				rio_dprintk(RIO_DEBUG_CMD, "Not ready to start command %p\n", CmdBlkP);
+			} else {
+				rio_dprintk(RIO_DEBUG_CMD, "Start new command %p Cmd byte is 0x%x\n", CmdBlkP, CmdBlkP->Packet.data[0]);
+				/*
+				 ** Whammy! blat that pack!
+				 */
+				HostP->Copy(&CmdBlkP->Packet, RIO_PTR(HostP->Caddr, readw(&UnixRupP->RupP->txpkt)), sizeof(struct PKT));
+
+				/*
+				 ** remove the command from the rup command queue...
+				 */
+				UnixRupP->CmdsWaitingP = CmdBlkP->NextP;
+
+				/*
+				 ** ...and place it on the pending position.
+				 */
+				UnixRupP->CmdPendingP = CmdBlkP;
+
+				/*
+				 ** set the command register
+				 */
+				writew(TX_PACKET_READY, &UnixRupP->RupP->txcontrol);
+
+				/*
+				 ** the command block will be freed
+				 ** when the command has been processed.
+				 */
+			}
+		}
+		spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
+	} while (Rup);
+}
+
+int RIOWFlushMark(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+	struct Port *PortP = (struct Port *) iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	PortP->WflushFlag++;
+	PortP->MagicFlags |= MAGIC_FLUSH;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse(iPortP, CmdBlkP);
+}
+
+int RIORFlushEnable(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+	struct Port *PortP = (struct Port *) iPortP;
+	struct PKT __iomem *PacketP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	while (can_remove_receive(&PacketP, PortP)) {
+		remove_receive(PortP);
+		put_free_end(PortP->HostP, PacketP);
+	}
+
+	if (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET) {
+		/*
+		 ** MAGIC! (Basically, handshake the RX buffer, so that
+		 ** the RTAs upstream can be re-enabled.)
+		 */
+		rio_dprintk(RIO_DEBUG_CMD, "Util: Set RX handshake bit\n");
+		writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);
+	}
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return RIOUnUse(iPortP, CmdBlkP);
+}
+
+int RIOUnUse(unsigned long iPortP, struct CmdBlk *CmdBlkP)
+{
+	struct Port *PortP = (struct Port *) iPortP;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	rio_dprintk(RIO_DEBUG_CMD, "Decrement in use count for port\n");
+
+	if (PortP->InUse) {
+		if (--PortP->InUse != NOT_INUSE) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return 0;
+		}
+	}
+	/*
+	 ** While PortP->InUse is set (i.e. a preemptive command has been sent to
+	 ** the RTA and is awaiting completion), any transmit data is prevented from
+	 ** being transferred from the write queue into the transmit packets
+	 ** (add_transmit) and no furthur transmit interrupt will be sent for that
+	 ** data. The next interrupt will occur up to 500ms later (RIOIntr is called
+	 ** twice a second as a saftey measure). This was the case when kermit was
+	 ** used to send data into a RIO port. After each packet was sent, TCFLSH
+	 ** was called to flush the read queue preemptively. PortP->InUse was
+	 ** incremented, thereby blocking the 6 byte acknowledgement packet
+	 ** transmitted back. This acknowledgment hung around for 500ms before
+	 ** being sent, thus reducing input performance substantially!.
+	 ** When PortP->InUse becomes NOT_INUSE, we must ensure that any data
+	 ** hanging around in the transmit buffer is sent immediately.
+	 */
+	writew(1, &PortP->HostP->ParmMapP->tx_intr);
+	/* What to do here ..
+	   wakeup( (caddr_t)&(PortP->InUse) );
+	 */
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return 0;
+}
+
+/*
+** 
+** How to use this file:
+** 
+** To send a command down a rup, you need to allocate a command block, fill
+** in the packet information, fill in the command number, fill in the pre-
+** and post- functions and arguments, and then add the command block to the
+** queue of command blocks for the port in question. When the port is idle,
+** then the pre-function will be called. If this returns RIO_FAIL then the
+** command will be re-queued and tried again at a later date (probably in one
+** clock tick). If the pre-function returns NOT RIO_FAIL, then the command
+** packet will be queued on the RUP, and the txcontrol field set to the
+** command number. When the txcontrol field has changed from being the
+** command number, then the post-function will be called, with the argument
+** specified earlier, a pointer to the command block, and the value of
+** txcontrol.
+** 
+** To allocate a command block, call RIOGetCmdBlk(). This returns a pointer
+** to the command block structure allocated, or NULL if there aren't any.
+** The block will have been zeroed for you.
+** 
+** The structure has the following fields:
+** 
+** struct CmdBlk
+** {
+**	 struct CmdBlk *NextP;		  ** Pointer to next command block   **
+**	 struct PKT	 Packet;		** A packet, to copy to the rup	**
+**			int	 (*PreFuncP)();  ** The func to call to check if OK **
+**			int	 PreArg;		** The arg for the func			**
+**			int	 (*PostFuncP)(); ** The func to call when completed **
+**			int	 PostArg;	   ** The arg for the func			**
+** };
+** 
+** You need to fill in ALL fields EXCEPT NextP, which is used to link the
+** blocks together either on the free list or on the Rup list.
+** 
+** Packet is an actual packet structure to be filled in with the packet
+** information associated with the command. You need to fill in everything,
+** as the command processor doesn't process the command packet in any way.
+** 
+** The PreFuncP is called before the packet is enqueued on the host rup.
+** PreFuncP is called as (*PreFuncP)(PreArg, CmdBlkP);. PreFuncP must
+** return !RIO_FAIL to have the packet queued on the rup, and RIO_FAIL
+** if the packet is NOT to be queued.
+** 
+** The PostFuncP is called when the command has completed. It is called
+** as (*PostFuncP)(PostArg, CmdBlkP, txcontrol);. PostFuncP is not expected
+** to return a value. PostFuncP does NOT need to free the command block,
+** as this happens automatically after PostFuncP returns.
+** 
+** Once the command block has been filled in, it is attached to the correct
+** queue by calling RIOQueueCmdBlk( HostP, Rup, CmdBlkP ) where HostP is
+** a pointer to the struct Host, Rup is the NUMBER of the rup (NOT a pointer
+** to it!), and CmdBlkP is the pointer to the command block allocated using
+** RIOGetCmdBlk().
+** 
+*/
diff --git a/drivers/staging/generic_serial/rio/rioctrl.c b/drivers/staging/generic_serial/rio/rioctrl.c
new file mode 100644
index 0000000..7805063
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioctrl.c
@@ -0,0 +1,1504 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioctrl.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:42
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioctrl.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static struct LpbReq LpbReq;
+static struct RupReq RupReq;
+static struct PortReq PortReq;
+static struct HostReq HostReq;	/* oh really?  global?  and no locking? */
+static struct HostDpRam HostDpRam;
+static struct DebugCtrl DebugCtrl;
+static struct Map MapEnt;
+static struct PortSetup PortSetup;
+static struct DownLoad DownLoad;
+static struct SendPack SendPack;
+/* static struct StreamInfo	StreamInfo; */
+/* static char modemtable[RIO_PORTS]; */
+static struct SpecialRupCmd SpecialRupCmd;
+static struct PortParams PortParams;
+static struct portStats portStats;
+
+static struct SubCmdStruct {
+	ushort Host;
+	ushort Rup;
+	ushort Port;
+	ushort Addr;
+} SubCmd;
+
+struct PortTty {
+	uint port;
+	struct ttystatics Tty;
+};
+
+static struct PortTty PortTty;
+typedef struct ttystatics TERMIO;
+
+/*
+** This table is used when the config.rio downloads bin code to the
+** driver. We index the table using the product code, 0-F, and call
+** the function pointed to by the entry, passing the information
+** about the boot.
+** The RIOBootCodeUNKNOWN entry is there to politely tell the calling
+** process to bog off.
+*/
+static int
+ (*RIOBootTable[MAX_PRODUCT]) (struct rio_info *, struct DownLoad *) = {
+					/* 0 */ RIOBootCodeHOST,
+					/* Host Card */
+					/* 1 */ RIOBootCodeRTA,
+					/* RTA */
+};
+
+#define drv_makedev(maj, min) ((((uint) maj & 0xff) << 8) | ((uint) min & 0xff))
+
+static int copy_from_io(void __user *to, void __iomem *from, size_t size)
+{
+	void *buf = kmalloc(size, GFP_KERNEL);
+	int res = -ENOMEM;
+	if (buf) {
+		rio_memcpy_fromio(buf, from, size);
+		res = copy_to_user(to, buf, size);
+		kfree(buf);
+	}
+	return res;
+}
+
+int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su)
+{
+	uint Host;		/* leave me unsigned! */
+	uint port;		/* and me! */
+	struct Host *HostP;
+	ushort loop;
+	int Entry;
+	struct Port *PortP;
+	struct PKT __iomem *PacketP;
+	int retval = 0;
+	unsigned long flags;
+	void __user *argp = (void __user *)arg;
+
+	func_enter();
+
+	/* Confuse the compiler to think that we've initialized these */
+	Host = 0;
+	PortP = NULL;
+
+	rio_dprintk(RIO_DEBUG_CTRL, "control ioctl cmd: 0x%x arg: %p\n", cmd, argp);
+
+	switch (cmd) {
+		/*
+		 ** RIO_SET_TIMER
+		 **
+		 ** Change the value of the host card interrupt timer.
+		 ** If the host card number is -1 then all host cards are changed
+		 ** otherwise just the specified host card will be changed.
+		 */
+	case RIO_SET_TIMER:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_TIMER to %ldms\n", arg);
+		{
+			int host, value;
+			host = (arg >> 16) & 0x0000FFFF;
+			value = arg & 0x0000ffff;
+			if (host == -1) {
+				for (host = 0; host < p->RIONumHosts; host++) {
+					if (p->RIOHosts[host].Flags == RC_RUNNING) {
+						writew(value, &p->RIOHosts[host].ParmMapP->timer);
+					}
+				}
+			} else if (host >= p->RIONumHosts) {
+				return -EINVAL;
+			} else {
+				if (p->RIOHosts[host].Flags == RC_RUNNING) {
+					writew(value, &p->RIOHosts[host].ParmMapP->timer);
+				}
+			}
+		}
+		return 0;
+
+	case RIO_FOAD_RTA:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_FOAD_RTA\n");
+		return RIOCommandRta(p, arg, RIOFoadRta);
+
+	case RIO_ZOMBIE_RTA:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_ZOMBIE_RTA\n");
+		return RIOCommandRta(p, arg, RIOZombieRta);
+
+	case RIO_IDENTIFY_RTA:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_IDENTIFY_RTA\n");
+		return RIOIdentifyRta(p, argp);
+
+	case RIO_KILL_NEIGHBOUR:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_KILL_NEIGHBOUR\n");
+		return RIOKillNeighbour(p, argp);
+
+	case SPECIAL_RUP_CMD:
+		{
+			struct CmdBlk *CmdBlkP;
+
+			rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD\n");
+			if (copy_from_user(&SpecialRupCmd, argp, sizeof(SpecialRupCmd))) {
+				rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD copy failed\n");
+				p->RIOError.Error = COPYIN_FAILED;
+				return -EFAULT;
+			}
+			CmdBlkP = RIOGetCmdBlk();
+			if (!CmdBlkP) {
+				rio_dprintk(RIO_DEBUG_CTRL, "SPECIAL_RUP_CMD GetCmdBlk failed\n");
+				return -ENXIO;
+			}
+			CmdBlkP->Packet = SpecialRupCmd.Packet;
+			if (SpecialRupCmd.Host >= p->RIONumHosts)
+				SpecialRupCmd.Host = 0;
+			rio_dprintk(RIO_DEBUG_CTRL, "Queue special rup command for host %d rup %d\n", SpecialRupCmd.Host, SpecialRupCmd.RupNum);
+			if (RIOQueueCmdBlk(&p->RIOHosts[SpecialRupCmd.Host], SpecialRupCmd.RupNum, CmdBlkP) == RIO_FAIL) {
+				printk(KERN_WARNING "rio: FAILED TO QUEUE SPECIAL RUP COMMAND\n");
+			}
+			return 0;
+		}
+
+	case RIO_DEBUG_MEM:
+		return -EPERM;
+
+	case RIO_ALL_MODEM:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_ALL_MODEM\n");
+		p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+		return -EINVAL;
+
+	case RIO_GET_TABLE:
+		/*
+		 ** Read the routing table from the device driver to user space
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_TABLE\n");
+
+		if ((retval = RIOApel(p)) != 0)
+			return retval;
+
+		if (copy_to_user(argp, p->RIOConnectTable, TOTAL_MAP_ENTRIES * sizeof(struct Map))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_TABLE copy failed\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+
+		{
+			int entry;
+			rio_dprintk(RIO_DEBUG_CTRL, "*****\nMAP ENTRIES\n");
+			for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+				if ((p->RIOConnectTable[entry].ID == 0) && (p->RIOConnectTable[entry].HostUniqueNum == 0) && (p->RIOConnectTable[entry].RtaUniqueNum == 0))
+					continue;
+
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Flags = 0x%x\n", entry, (int) p->RIOConnectTable[entry].Flags);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.SysPort = 0x%x\n", entry, (int) p->RIOConnectTable[entry].SysPort);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[0].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Unit);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[0].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[0].Link);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[1].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Unit);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[1].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[1].Link);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[2].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Unit);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[2].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[2].Link);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[3].Unit = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Unit);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Top[4].Link = %x\n", entry, p->RIOConnectTable[entry].Topology[3].Link);
+				rio_dprintk(RIO_DEBUG_CTRL, "Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name);
+			}
+			rio_dprintk(RIO_DEBUG_CTRL, "*****\nEND MAP ENTRIES\n");
+		}
+		p->RIOQuickCheck = NOT_CHANGED;	/* a table has been gotten */
+		return 0;
+
+	case RIO_PUT_TABLE:
+		/*
+		 ** Write the routing table to the device driver from user space
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE\n");
+
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&p->RIOConnectTable[0], argp, TOTAL_MAP_ENTRIES * sizeof(struct Map))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_TABLE copy failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+/*
+***********************************
+				{
+					int entry;
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nMAP ENTRIES\n") );
+					for ( entry=0; entry<TOTAL_MAP_ENTRIES; entry++ )
+					{
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.HostUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].HostUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.RtaUniqueNum = 0x%x\n", entry, p->RIOConnectTable[entry].RtaUniqueNum ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID = 0x%x\n", entry, p->RIOConnectTable[entry].ID ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.ID2 = 0x%x\n", entry, p->RIOConnectTable[entry].ID2 ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Flags = 0x%x\n", entry, p->RIOConnectTable[entry].Flags ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.SysPort = 0x%x\n", entry, p->RIOConnectTable[entry].SysPort ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[0].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[0].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[1].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[1].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[2].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[2].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[3].Unit = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Unit ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Top[4].Link = %b\n", entry, p->RIOConnectTable[entry].Topology[3].Link ) );
+						rio_dprint(RIO_DEBUG_CTRL,  ("Map entry %d.Name = %s\n", entry, p->RIOConnectTable[entry].Name ) );
+					}
+					rio_dprint(RIO_DEBUG_CTRL,  ("*****\nEND MAP ENTRIES\n") );
+				}
+***********************************
+*/
+		return RIONewTable(p);
+
+	case RIO_GET_BINDINGS:
+		/*
+		 ** Send bindings table, containing unique numbers of RTAs owned
+		 ** by this system to user space
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS\n");
+
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_to_user(argp, p->RIOBindTab, (sizeof(ulong) * MAX_RTA_BINDINGS))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_BINDINGS copy failed\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_PUT_BINDINGS:
+		/*
+		 ** Receive a bindings table, containing unique numbers of RTAs owned
+		 ** by this system
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS\n");
+
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&p->RIOBindTab[0], argp, (sizeof(ulong) * MAX_RTA_BINDINGS))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_PUT_BINDINGS copy failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_BIND_RTA:
+		{
+			int EmptySlot = -1;
+			/*
+			 ** Bind this RTA to host, so that it will be booted by
+			 ** host in 'boot owned RTAs' mode.
+			 */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_BIND_RTA\n");
+
+			if (!su) {
+				rio_dprintk(RIO_DEBUG_CTRL, "RIO_BIND_RTA !Root\n");
+				p->RIOError.Error = NOT_SUPER_USER;
+				return -EPERM;
+			}
+			for (Entry = 0; Entry < MAX_RTA_BINDINGS; Entry++) {
+				if ((EmptySlot == -1) && (p->RIOBindTab[Entry] == 0L))
+					EmptySlot = Entry;
+				else if (p->RIOBindTab[Entry] == arg) {
+					/*
+					 ** Already exists - delete
+					 */
+					p->RIOBindTab[Entry] = 0L;
+					rio_dprintk(RIO_DEBUG_CTRL, "Removing Rta %ld from p->RIOBindTab\n", arg);
+					return 0;
+				}
+			}
+			/*
+			 ** Dosen't exist - add
+			 */
+			if (EmptySlot != -1) {
+				p->RIOBindTab[EmptySlot] = arg;
+				rio_dprintk(RIO_DEBUG_CTRL, "Adding Rta %lx to p->RIOBindTab\n", arg);
+			} else {
+				rio_dprintk(RIO_DEBUG_CTRL, "p->RIOBindTab full! - Rta %lx not added\n", arg);
+				return -ENOMEM;
+			}
+			return 0;
+		}
+
+	case RIO_RESUME:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME\n");
+		port = arg;
+		if ((port < 0) || (port > 511)) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Bad port number %d\n", port);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		PortP = p->RIOPortp[port];
+		if (!PortP->Mapped) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not mapped\n", port);
+			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+			return -EINVAL;
+		}
+		if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d not open\n", port);
+			return -EINVAL;
+		}
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) ==
+				RIO_FAIL) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n");
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return -EBUSY;
+		} else {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME: Port %d resumed\n", port);
+			PortP->State |= RIO_BUSY;
+		}
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_ASSIGN_RTA:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA\n");
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_ASSIGN_RTA !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Copy from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		return RIOAssignRta(p, &MapEnt);
+
+	case RIO_CHANGE_NAME:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_CHANGE_NAME\n");
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_CHANGE_NAME !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Copy from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		return RIOChangeName(p, &MapEnt);
+
+	case RIO_DELETE_RTA:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_DELETE_RTA\n");
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_DELETE_RTA !Root\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&MapEnt, argp, sizeof(MapEnt))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Copy from data space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		return RIODeleteRta(p, &MapEnt);
+
+	case RIO_QUICK_CHECK:
+		if (copy_to_user(argp, &p->RIORtaDisCons, sizeof(unsigned int))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_LAST_ERROR:
+		if (copy_to_user(argp, &p->RIOError, sizeof(struct Error)))
+			return -EFAULT;
+		return 0;
+
+	case RIO_GET_LOG:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_LOG\n");
+		return -EINVAL;
+
+	case RIO_GET_MODTYPE:
+		if (copy_from_user(&port, argp, sizeof(unsigned int))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Get module type for port %d\n", port);
+		if (port < 0 || port > 511) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Bad port number %d\n", port);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		PortP = (p->RIOPortp[port]);
+		if (!PortP->Mapped) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_MODTYPE: Port %d not mapped\n", port);
+			p->RIOError.Error = PORT_NOT_MAPPED_INTO_SYSTEM;
+			return -EINVAL;
+		}
+		/*
+		 ** Return module type of port
+		 */
+		port = PortP->HostP->UnixRups[PortP->RupNum].ModTypes;
+		if (copy_to_user(argp, &port, sizeof(unsigned int))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return (0);
+	case RIO_BLOCK_OPENS:
+		rio_dprintk(RIO_DEBUG_CTRL, "Opens block until booted\n");
+		for (Entry = 0; Entry < RIO_PORTS; Entry++) {
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			p->RIOPortp[Entry]->WaitUntilBooted = 1;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		}
+		return 0;
+
+	case RIO_SETUP_PORTS:
+		rio_dprintk(RIO_DEBUG_CTRL, "Setup ports\n");
+		if (copy_from_user(&PortSetup, argp, sizeof(PortSetup))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			rio_dprintk(RIO_DEBUG_CTRL, "EFAULT");
+			return -EFAULT;
+		}
+		if (PortSetup.From > PortSetup.To || PortSetup.To >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			rio_dprintk(RIO_DEBUG_CTRL, "ENXIO");
+			return -ENXIO;
+		}
+		if (PortSetup.XpCps > p->RIOConf.MaxXpCps || PortSetup.XpCps < p->RIOConf.MinXpCps) {
+			p->RIOError.Error = XPRINT_CPS_OUT_OF_RANGE;
+			rio_dprintk(RIO_DEBUG_CTRL, "EINVAL");
+			return -EINVAL;
+		}
+		if (!p->RIOPortp) {
+			printk(KERN_ERR "rio: No p->RIOPortp array!\n");
+			rio_dprintk(RIO_DEBUG_CTRL, "No p->RIOPortp array!\n");
+			return -EIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "entering loop (%d %d)!\n", PortSetup.From, PortSetup.To);
+		for (loop = PortSetup.From; loop <= PortSetup.To; loop++) {
+			rio_dprintk(RIO_DEBUG_CTRL, "in loop (%d)!\n", loop);
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "after loop (%d)!\n", loop);
+		rio_dprintk(RIO_DEBUG_CTRL, "Retval:%x\n", retval);
+		return retval;
+
+	case RIO_GET_PORT_SETUP:
+		rio_dprintk(RIO_DEBUG_CTRL, "Get port setup\n");
+		if (copy_from_user(&PortSetup, argp, sizeof(PortSetup))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (PortSetup.From >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+
+		port = PortSetup.To = PortSetup.From;
+		PortSetup.IxAny = (p->RIOPortp[port]->Config & RIO_IXANY) ? 1 : 0;
+		PortSetup.IxOn = (p->RIOPortp[port]->Config & RIO_IXON) ? 1 : 0;
+		PortSetup.Drain = (p->RIOPortp[port]->Config & RIO_WAITDRAIN) ? 1 : 0;
+		PortSetup.Store = p->RIOPortp[port]->Store;
+		PortSetup.Lock = p->RIOPortp[port]->Lock;
+		PortSetup.XpCps = p->RIOPortp[port]->Xprint.XpCps;
+		memcpy(PortSetup.XpOn, p->RIOPortp[port]->Xprint.XpOn, MAX_XP_CTRL_LEN);
+		memcpy(PortSetup.XpOff, p->RIOPortp[port]->Xprint.XpOff, MAX_XP_CTRL_LEN);
+		PortSetup.XpOn[MAX_XP_CTRL_LEN - 1] = '\0';
+		PortSetup.XpOff[MAX_XP_CTRL_LEN - 1] = '\0';
+
+		if (copy_to_user(argp, &PortSetup, sizeof(PortSetup))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_GET_PORT_PARAMS:
+		rio_dprintk(RIO_DEBUG_CTRL, "Get port params\n");
+		if (copy_from_user(&PortParams, argp, sizeof(struct PortParams))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (PortParams.Port >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[PortParams.Port]);
+		PortParams.Config = PortP->Config;
+		PortParams.State = PortP->State;
+		rio_dprintk(RIO_DEBUG_CTRL, "Port %d\n", PortParams.Port);
+
+		if (copy_to_user(argp, &PortParams, sizeof(struct PortParams))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_GET_PORT_TTY:
+		rio_dprintk(RIO_DEBUG_CTRL, "Get port tty\n");
+		if (copy_from_user(&PortTty, argp, sizeof(struct PortTty))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (PortTty.port >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+
+		rio_dprintk(RIO_DEBUG_CTRL, "Port %d\n", PortTty.port);
+		PortP = (p->RIOPortp[PortTty.port]);
+		if (copy_to_user(argp, &PortTty, sizeof(struct PortTty))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_SET_PORT_TTY:
+		if (copy_from_user(&PortTty, argp, sizeof(struct PortTty))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Set port %d tty\n", PortTty.port);
+		if (PortTty.port >= (ushort) RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[PortTty.port]);
+		RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM,
+				OK_TO_SLEEP);
+		return retval;
+
+	case RIO_SET_PORT_PARAMS:
+		rio_dprintk(RIO_DEBUG_CTRL, "Set port params\n");
+		if (copy_from_user(&PortParams, argp, sizeof(PortParams))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (PortParams.Port >= (ushort) RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[PortParams.Port]);
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->Config = PortParams.Config;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_GET_PORT_STATS:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_GET_PORT_STATS\n");
+		if (copy_from_user(&portStats, argp, sizeof(struct portStats))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[portStats.port]);
+		portStats.gather = PortP->statsGather;
+		portStats.txchars = PortP->txchars;
+		portStats.rxchars = PortP->rxchars;
+		portStats.opens = PortP->opens;
+		portStats.closes = PortP->closes;
+		portStats.ioctls = PortP->ioctls;
+		if (copy_to_user(argp, &portStats, sizeof(struct portStats))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_RESET_PORT_STATS:
+		port = arg;
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESET_PORT_STATS\n");
+		if (port >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[port]);
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->txchars = 0;
+		PortP->rxchars = 0;
+		PortP->opens = 0;
+		PortP->closes = 0;
+		PortP->ioctls = 0;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_GATHER_PORT_STATS:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_GATHER_PORT_STATS\n");
+		if (copy_from_user(&portStats, argp, sizeof(struct portStats))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		PortP = (p->RIOPortp[portStats.port]);
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->statsGather = portStats.gather;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_READ_CONFIG:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_CONFIG\n");
+		if (copy_to_user(argp, &p->RIOConf, sizeof(struct Conf))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_SET_CONFIG:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_CONFIG\n");
+		if (!su) {
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&p->RIOConf, argp, sizeof(struct Conf))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		/*
+		 ** move a few value around
+		 */
+		for (Host = 0; Host < p->RIONumHosts; Host++)
+			if ((p->RIOHosts[Host].Flags & RUN_STATE) == RC_RUNNING)
+				writew(p->RIOConf.Timer, &p->RIOHosts[Host].ParmMapP->timer);
+		return retval;
+
+	case RIO_START_POLLER:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_START_POLLER\n");
+		return -EINVAL;
+
+	case RIO_STOP_POLLER:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_STOP_POLLER\n");
+		if (!su) {
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		p->RIOPolling = NOT_POLLING;
+		return retval;
+
+	case RIO_SETDEBUG:
+	case RIO_GETDEBUG:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_SETDEBUG/RIO_GETDEBUG\n");
+		if (copy_from_user(&DebugCtrl, argp, sizeof(DebugCtrl))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (DebugCtrl.SysPort == NO_PORT) {
+			if (cmd == RIO_SETDEBUG) {
+				if (!su) {
+					p->RIOError.Error = NOT_SUPER_USER;
+					return -EPERM;
+				}
+				p->rio_debug = DebugCtrl.Debug;
+				p->RIODebugWait = DebugCtrl.Wait;
+				rio_dprintk(RIO_DEBUG_CTRL, "Set global debug to 0x%x set wait to 0x%x\n", p->rio_debug, p->RIODebugWait);
+			} else {
+				rio_dprintk(RIO_DEBUG_CTRL, "Get global debug 0x%x wait 0x%x\n", p->rio_debug, p->RIODebugWait);
+				DebugCtrl.Debug = p->rio_debug;
+				DebugCtrl.Wait = p->RIODebugWait;
+				if (copy_to_user(argp, &DebugCtrl, sizeof(DebugCtrl))) {
+					rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", DebugCtrl.SysPort);
+					p->RIOError.Error = COPYOUT_FAILED;
+					return -EFAULT;
+				}
+			}
+		} else if (DebugCtrl.SysPort >= RIO_PORTS && DebugCtrl.SysPort != NO_PORT) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET/GET DEBUG: bad port number %d\n", DebugCtrl.SysPort);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		} else if (cmd == RIO_SETDEBUG) {
+			if (!su) {
+				p->RIOError.Error = NOT_SUPER_USER;
+				return -EPERM;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			p->RIOPortp[DebugCtrl.SysPort]->Debug = DebugCtrl.Debug;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_SETDEBUG 0x%x\n", p->RIOPortp[DebugCtrl.SysPort]->Debug);
+		} else {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_GETDEBUG 0x%x\n", p->RIOPortp[DebugCtrl.SysPort]->Debug);
+			DebugCtrl.Debug = p->RIOPortp[DebugCtrl.SysPort]->Debug;
+			if (copy_to_user(argp, &DebugCtrl, sizeof(DebugCtrl))) {
+				rio_dprintk(RIO_DEBUG_CTRL, "RIO_GETDEBUG: Bad copy to user space\n");
+				p->RIOError.Error = COPYOUT_FAILED;
+				return -EFAULT;
+			}
+		}
+		return retval;
+
+	case RIO_VERSID:
+		/*
+		 ** Enquire about the release and version.
+		 ** We return MAX_VERSION_LEN bytes, being a
+		 ** textual null terminated string.
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_VERSID\n");
+		if (copy_to_user(argp, RIOVersid(), sizeof(struct rioVersion))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_VERSID: Bad copy to user space (host=%d)\n", Host);
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_NUM_HOSTS:
+		/*
+		 ** Enquire as to the number of hosts located
+		 ** at init time.
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_NUM_HOSTS\n");
+		if (copy_to_user(argp, &p->RIONumHosts, sizeof(p->RIONumHosts))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_NUM_HOSTS: Bad copy to user space\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_HOST_FOAD:
+		/*
+		 ** Kill host. This may not be in the final version...
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_FOAD %ld\n", arg);
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_FOAD: Not super user\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		p->RIOHalted = 1;
+		p->RIOSystemUp = 0;
+
+		for (Host = 0; Host < p->RIONumHosts; Host++) {
+			(void) RIOBoardTest(p->RIOHosts[Host].PaddrP, p->RIOHosts[Host].Caddr, p->RIOHosts[Host].Type, p->RIOHosts[Host].Slot);
+			memset(&p->RIOHosts[Host].Flags, 0, ((char *) &p->RIOHosts[Host].____end_marker____) - ((char *) &p->RIOHosts[Host].Flags));
+			p->RIOHosts[Host].Flags = RC_WAITING;
+		}
+		RIOFoadWakeup(p);
+		p->RIONumBootPkts = 0;
+		p->RIOBooting = 0;
+		printk("HEEEEELP!\n");
+
+		for (loop = 0; loop < RIO_PORTS; loop++) {
+			spin_lock_init(&p->RIOPortp[loop]->portSem);
+			p->RIOPortp[loop]->InUse = NOT_INUSE;
+		}
+
+		p->RIOSystemUp = 0;
+		return retval;
+
+	case RIO_DOWNLOAD:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD\n");
+		if (!su) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Not super user\n");
+			p->RIOError.Error = NOT_SUPER_USER;
+			return -EPERM;
+		}
+		if (copy_from_user(&DownLoad, argp, sizeof(DownLoad))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Copy in from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Copied in download code for product code 0x%x\n", DownLoad.ProductCode);
+
+		/*
+		 ** It is important that the product code is an unsigned object!
+		 */
+		if (DownLoad.ProductCode >= MAX_PRODUCT) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_DOWNLOAD: Bad product code %d passed\n", DownLoad.ProductCode);
+			p->RIOError.Error = NO_SUCH_PRODUCT;
+			return -ENXIO;
+		}
+		/*
+		 ** do something!
+		 */
+		retval = (*(RIOBootTable[DownLoad.ProductCode])) (p, &DownLoad);
+		/* <-- Panic */
+		p->RIOHalted = 0;
+		/*
+		 ** and go back, content with a job well completed.
+		 */
+		return retval;
+
+	case RIO_PARMS:
+		{
+			unsigned int host;
+
+			if (copy_from_user(&host, argp, sizeof(host))) {
+				rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n");
+				p->RIOError.Error = COPYIN_FAILED;
+				return -EFAULT;
+			}
+			/*
+			 ** Fetch the parmmap
+			 */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_PARMS\n");
+			if (copy_from_io(argp, p->RIOHosts[host].ParmMapP, sizeof(PARM_MAP))) {
+				p->RIOError.Error = COPYOUT_FAILED;
+				rio_dprintk(RIO_DEBUG_CTRL, "RIO_PARMS: Copy out to user space failed\n");
+				return -EFAULT;
+			}
+		}
+		return retval;
+
+	case RIO_HOST_REQ:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ\n");
+		if (copy_from_user(&HostReq, argp, sizeof(HostReq))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Copy in from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (HostReq.HostNum >= p->RIONumHosts) {
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Illegal host number %d\n", HostReq.HostNum);
+			return -ENXIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for host %d\n", HostReq.HostNum);
+
+		if (copy_to_user(HostReq.HostP, &p->RIOHosts[HostReq.HostNum], sizeof(struct Host))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_REQ: Bad copy to user space\n");
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_HOST_DPRAM:
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for DPRAM\n");
+		if (copy_from_user(&HostDpRam, argp, sizeof(HostDpRam))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Copy in from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (HostDpRam.HostNum >= p->RIONumHosts) {
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Illegal host number %d\n", HostDpRam.HostNum);
+			return -ENXIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for host %d\n", HostDpRam.HostNum);
+
+		if (p->RIOHosts[HostDpRam.HostNum].Type == RIO_PCI) {
+			int off;
+			/* It's hardware like this that really gets on my tits. */
+			static unsigned char copy[sizeof(struct DpRam)];
+			for (off = 0; off < sizeof(struct DpRam); off++)
+				copy[off] = readb(p->RIOHosts[HostDpRam.HostNum].Caddr + off);
+			if (copy_to_user(HostDpRam.DpRamP, copy, sizeof(struct DpRam))) {
+				p->RIOError.Error = COPYOUT_FAILED;
+				rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n");
+				return -EFAULT;
+			}
+		} else if (copy_from_io(HostDpRam.DpRamP, p->RIOHosts[HostDpRam.HostNum].Caddr, sizeof(struct DpRam))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_DPRAM: Bad copy to user space\n");
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_SET_BUSY:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_BUSY\n");
+		if (arg > 511) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_SET_BUSY: Bad port number %ld\n", arg);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		p->RIOPortp[arg]->State |= RIO_BUSY;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_HOST_PORT:
+		/*
+		 ** The daemon want port information
+		 ** (probably for debug reasons)
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT\n");
+		if (copy_from_user(&PortReq, argp, sizeof(PortReq))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Copy in from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+
+		if (PortReq.SysPort >= RIO_PORTS) {	/* SysPort is unsigned */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Illegal port number %d\n", PortReq.SysPort);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for port %d\n", PortReq.SysPort);
+		if (copy_to_user(PortReq.PortP, p->RIOPortp[PortReq.SysPort], sizeof(struct Port))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_PORT: Bad copy to user space\n");
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_HOST_RUP:
+		/*
+		 ** The daemon want rup information
+		 ** (probably for debug reasons)
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP\n");
+		if (copy_from_user(&RupReq, argp, sizeof(RupReq))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Copy in from user space failed\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (RupReq.HostNum >= p->RIONumHosts) {	/* host is unsigned */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal host number %d\n", RupReq.HostNum);
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		if (RupReq.RupNum >= MAX_RUP + LINKS_PER_UNIT) {	/* eek! */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Illegal rup number %d\n", RupReq.RupNum);
+			p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		HostP = &p->RIOHosts[RupReq.HostNum];
+
+		if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Host %d not running\n", RupReq.HostNum);
+			p->RIOError.Error = HOST_NOT_RUNNING;
+			return -EIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for rup %d from host %d\n", RupReq.RupNum, RupReq.HostNum);
+
+		if (copy_from_io(RupReq.RupP, HostP->UnixRups[RupReq.RupNum].RupP, sizeof(struct RUP))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_RUP: Bad copy to user space\n");
+			return -EFAULT;
+		}
+		return retval;
+
+	case RIO_HOST_LPB:
+		/*
+		 ** The daemon want lpb information
+		 ** (probably for debug reasons)
+		 */
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB\n");
+		if (copy_from_user(&LpbReq, argp, sizeof(LpbReq))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy from user space\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (LpbReq.Host >= p->RIONumHosts) {	/* host is unsigned */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal host number %d\n", LpbReq.Host);
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+		if (LpbReq.Link >= LINKS_PER_UNIT) {	/* eek! */
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Illegal link number %d\n", LpbReq.Link);
+			p->RIOError.Error = LINK_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		HostP = &p->RIOHosts[LpbReq.Host];
+
+		if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Host %d not running\n", LpbReq.Host);
+			p->RIOError.Error = HOST_NOT_RUNNING;
+			return -EIO;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Request for lpb %d from host %d\n", LpbReq.Link, LpbReq.Host);
+
+		if (copy_from_io(LpbReq.LpbP, &HostP->LinkStrP[LpbReq.Link], sizeof(struct LPB))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_HOST_LPB: Bad copy to user space\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return retval;
+
+		/*
+		 ** Here 3 IOCTL's that allow us to change the way in which
+		 ** rio logs errors. send them just to syslog or send them
+		 ** to both syslog and console or send them to just the console.
+		 **
+		 ** See RioStrBuf() in util.c for the other half.
+		 */
+	case RIO_SYSLOG_ONLY:
+		p->RIOPrintLogState = PRINT_TO_LOG;	/* Just syslog */
+		return 0;
+
+	case RIO_SYSLOG_CONS:
+		p->RIOPrintLogState = PRINT_TO_LOG_CONS;	/* syslog and console */
+		return 0;
+
+	case RIO_CONS_ONLY:
+		p->RIOPrintLogState = PRINT_TO_CONS;	/* Just console */
+		return 0;
+
+	case RIO_SIGNALS_ON:
+		if (p->RIOSignalProcess) {
+			p->RIOError.Error = SIGNALS_ALREADY_SET;
+			return -EBUSY;
+		}
+		/* FIXME: PID tracking */
+		p->RIOSignalProcess = current->pid;
+		p->RIOPrintDisabled = DONT_PRINT;
+		return retval;
+
+	case RIO_SIGNALS_OFF:
+		if (p->RIOSignalProcess != current->pid) {
+			p->RIOError.Error = NOT_RECEIVING_PROCESS;
+			return -EPERM;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "Clear signal process to zero\n");
+		p->RIOSignalProcess = 0;
+		return retval;
+
+	case RIO_SET_BYTE_MODE:
+		for (Host = 0; Host < p->RIONumHosts; Host++)
+			if (p->RIOHosts[Host].Type == RIO_AT)
+				p->RIOHosts[Host].Mode &= ~WORD_OPERATION;
+		return retval;
+
+	case RIO_SET_WORD_MODE:
+		for (Host = 0; Host < p->RIONumHosts; Host++)
+			if (p->RIOHosts[Host].Type == RIO_AT)
+				p->RIOHosts[Host].Mode |= WORD_OPERATION;
+		return retval;
+
+	case RIO_SET_FAST_BUS:
+		for (Host = 0; Host < p->RIONumHosts; Host++)
+			if (p->RIOHosts[Host].Type == RIO_AT)
+				p->RIOHosts[Host].Mode |= FAST_AT_BUS;
+		return retval;
+
+	case RIO_SET_SLOW_BUS:
+		for (Host = 0; Host < p->RIONumHosts; Host++)
+			if (p->RIOHosts[Host].Type == RIO_AT)
+				p->RIOHosts[Host].Mode &= ~FAST_AT_BUS;
+		return retval;
+
+	case RIO_MAP_B50_TO_50:
+	case RIO_MAP_B50_TO_57600:
+	case RIO_MAP_B110_TO_110:
+	case RIO_MAP_B110_TO_115200:
+		rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping\n");
+		port = arg;
+		if (port < 0 || port > 511) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", port);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		switch (cmd) {
+		case RIO_MAP_B50_TO_50:
+			p->RIOPortp[port]->Config |= RIO_MAP_50_TO_50;
+			break;
+		case RIO_MAP_B50_TO_57600:
+			p->RIOPortp[port]->Config &= ~RIO_MAP_50_TO_50;
+			break;
+		case RIO_MAP_B110_TO_110:
+			p->RIOPortp[port]->Config |= RIO_MAP_110_TO_110;
+			break;
+		case RIO_MAP_B110_TO_115200:
+			p->RIOPortp[port]->Config &= ~RIO_MAP_110_TO_110;
+			break;
+		}
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_STREAM_INFO:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_STREAM_INFO\n");
+		return -EINVAL;
+
+	case RIO_SEND_PACKET:
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_SEND_PACKET\n");
+		if (copy_from_user(&SendPack, argp, sizeof(SendPack))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_SEND_PACKET: Bad copy from user space\n");
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		if (SendPack.PortNum >= 128) {
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -ENXIO;
+		}
+
+		PortP = p->RIOPortp[SendPack.PortNum];
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		if (!can_add_transmit(&PacketP, PortP)) {
+			p->RIOError.Error = UNIT_IS_IN_USE;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return -ENOSPC;
+		}
+
+		for (loop = 0; loop < (ushort) (SendPack.Len & 127); loop++)
+			writeb(SendPack.Data[loop], &PacketP->data[loop]);
+
+		writeb(SendPack.Len, &PacketP->len);
+
+		add_transmit(PortP);
+		/*
+		 ** Count characters transmitted for port statistics reporting
+		 */
+		if (PortP->statsGather)
+			PortP->txchars += (SendPack.Len & 127);
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return retval;
+
+	case RIO_NO_MESG:
+		if (su)
+			p->RIONoMessage = 1;
+		return su ? 0 : -EPERM;
+
+	case RIO_MESG:
+		if (su)
+			p->RIONoMessage = 0;
+		return su ? 0 : -EPERM;
+
+	case RIO_WHAT_MESG:
+		if (copy_to_user(argp, &p->RIONoMessage, sizeof(p->RIONoMessage))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_WHAT_MESG: Bad copy to user space\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_MEM_DUMP:
+		if (copy_from_user(&SubCmd, argp, sizeof(struct SubCmdStruct))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP host %d rup %d addr %x\n", SubCmd.Host, SubCmd.Rup, SubCmd.Addr);
+
+		if (SubCmd.Rup >= MAX_RUP + LINKS_PER_UNIT) {
+			p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+
+		if (SubCmd.Host >= p->RIONumHosts) {
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+
+		port = p->RIOHosts[SubCmd.Host].UnixRups[SubCmd.Rup].BaseSysPort;
+
+		PortP = p->RIOPortp[port];
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n");
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return -EBUSY;
+		} else
+			PortP->State |= RIO_BUSY;
+
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (copy_to_user(argp, p->RIOMemDump, MEMDUMP_SIZE)) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP copy failed\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_TICK:
+		if (arg >= p->RIONumHosts)
+			return -EINVAL;
+		rio_dprintk(RIO_DEBUG_CTRL, "Set interrupt for host %ld\n", arg);
+		writeb(0xFF, &p->RIOHosts[arg].SetInt);
+		return 0;
+
+	case RIO_TOCK:
+		if (arg >= p->RIONumHosts)
+			return -EINVAL;
+		rio_dprintk(RIO_DEBUG_CTRL, "Clear interrupt for host %ld\n", arg);
+		writeb(0xFF, &p->RIOHosts[arg].ResetInt);
+		return 0;
+
+	case RIO_READ_CHECK:
+		/* Check reads for pkts with data[0] the same */
+		p->RIOReadCheck = !p->RIOReadCheck;
+		if (copy_to_user(argp, &p->RIOReadCheck, sizeof(unsigned int))) {
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+
+	case RIO_READ_REGISTER:
+		if (copy_from_user(&SubCmd, argp, sizeof(struct SubCmdStruct))) {
+			p->RIOError.Error = COPYIN_FAILED;
+			return -EFAULT;
+		}
+		rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER host %d rup %d port %d reg %x\n", SubCmd.Host, SubCmd.Rup, SubCmd.Port, SubCmd.Addr);
+
+		if (SubCmd.Port > 511) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Baud rate mapping: Bad port number %d\n", SubCmd.Port);
+			p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+
+		if (SubCmd.Rup >= MAX_RUP + LINKS_PER_UNIT) {
+			p->RIOError.Error = RUP_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+
+		if (SubCmd.Host >= p->RIONumHosts) {
+			p->RIOError.Error = HOST_NUMBER_OUT_OF_RANGE;
+			return -EINVAL;
+		}
+
+		port = p->RIOHosts[SubCmd.Host].UnixRups[SubCmd.Rup].BaseSysPort + SubCmd.Port;
+		PortP = p->RIOPortp[port];
+
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) ==
+				RIO_FAIL) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n");
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return -EBUSY;
+		} else
+			PortP->State |= RIO_BUSY;
+
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (copy_to_user(argp, &p->CdRegister, sizeof(unsigned int))) {
+			rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER copy failed\n");
+			p->RIOError.Error = COPYOUT_FAILED;
+			return -EFAULT;
+		}
+		return 0;
+		/*
+		 ** rio_make_dev: given port number (0-511) ORed with port type
+		 ** (RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT) return dev_t
+		 ** value to pass to mknod to create the correct device node.
+		 */
+	case RIO_MAKE_DEV:
+		{
+			unsigned int port = arg & RIO_MODEM_MASK;
+			unsigned int ret;
+
+			switch (arg & RIO_DEV_MASK) {
+			case RIO_DEV_DIRECT:
+				ret = drv_makedev(MAJOR(dev), port);
+				rio_dprintk(RIO_DEBUG_CTRL, "Makedev direct 0x%x is 0x%x\n", port, ret);
+				return ret;
+			case RIO_DEV_MODEM:
+				ret = drv_makedev(MAJOR(dev), (port | RIO_MODEM_BIT));
+				rio_dprintk(RIO_DEBUG_CTRL, "Makedev modem 0x%x is 0x%x\n", port, ret);
+				return ret;
+			case RIO_DEV_XPRINT:
+				ret = drv_makedev(MAJOR(dev), port);
+				rio_dprintk(RIO_DEBUG_CTRL, "Makedev printer 0x%x is 0x%x\n", port, ret);
+				return ret;
+			}
+			rio_dprintk(RIO_DEBUG_CTRL, "MAKE Device is called\n");
+			return -EINVAL;
+		}
+		/*
+		 ** rio_minor: given a dev_t from a stat() call, return
+		 ** the port number (0-511) ORed with the port type
+		 ** ( RIO_DEV_DIRECT, RIO_DEV_MODEM, RIO_DEV_XPRINT )
+		 */
+	case RIO_MINOR:
+		{
+			dev_t dv;
+			int mino;
+			unsigned long ret;
+
+			dv = (dev_t) (arg);
+			mino = RIO_UNMODEM(dv);
+
+			if (RIO_ISMODEM(dv)) {
+				rio_dprintk(RIO_DEBUG_CTRL, "Minor for device 0x%x: modem %d\n", dv, mino);
+				ret = mino | RIO_DEV_MODEM;
+			} else {
+				rio_dprintk(RIO_DEBUG_CTRL, "Minor for device 0x%x: direct %d\n", dv, mino);
+				ret = mino | RIO_DEV_DIRECT;
+			}
+			return ret;
+		}
+	}
+	rio_dprintk(RIO_DEBUG_CTRL, "INVALID DAEMON IOCTL 0x%x\n", cmd);
+	p->RIOError.Error = IOCTL_COMMAND_UNKNOWN;
+
+	func_exit();
+	return -EINVAL;
+}
+
+/*
+** Pre-emptive commands go on RUPs and are only one byte long.
+*/
+int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd)
+{
+	struct CmdBlk *CmdBlkP;
+	struct PktCmd_M *PktCmdP;
+	int Ret;
+	ushort rup;
+	int port;
+
+	if (PortP->State & RIO_DELETED) {
+		rio_dprintk(RIO_DEBUG_CTRL, "Preemptive command to deleted RTA ignored\n");
+		return RIO_FAIL;
+	}
+
+	if ((PortP->InUse == (typeof(PortP->InUse))-1) ||
+			!(CmdBlkP = RIOGetCmdBlk())) {
+		rio_dprintk(RIO_DEBUG_CTRL, "Cannot allocate command block "
+			"for command %d on port %d\n", Cmd, PortP->PortNum);
+		return RIO_FAIL;
+	}
+
+	rio_dprintk(RIO_DEBUG_CTRL, "Command blk %p - InUse now %d\n",
+			CmdBlkP, PortP->InUse);
+
+	PktCmdP = (struct PktCmd_M *)&CmdBlkP->Packet.data[0];
+
+	CmdBlkP->Packet.src_unit = 0;
+	if (PortP->SecondBlock)
+		rup = PortP->ID2;
+	else
+		rup = PortP->RupNum;
+	CmdBlkP->Packet.dest_unit = rup;
+	CmdBlkP->Packet.src_port = COMMAND_RUP;
+	CmdBlkP->Packet.dest_port = COMMAND_RUP;
+	CmdBlkP->Packet.len = PKT_CMD_BIT | 2;
+	CmdBlkP->PostFuncP = RIOUnUse;
+	CmdBlkP->PostArg = (unsigned long) PortP;
+	PktCmdP->Command = Cmd;
+	port = PortP->HostPort % (ushort) PORTS_PER_RTA;
+	/*
+	 ** Index ports 8-15 for 2nd block of 16 port RTA.
+	 */
+	if (PortP->SecondBlock)
+		port += (ushort) PORTS_PER_RTA;
+	PktCmdP->PhbNum = port;
+
+	switch (Cmd) {
+	case RIOC_MEMDUMP:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
+				"(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
+		PktCmdP->SubCommand = RIOC_MEMDUMP;
+		PktCmdP->SubAddr = SubCmd.Addr;
+		break;
+	case RIOC_FCLOSE:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
+				CmdBlkP);
+		break;
+	case RIOC_READ_REGISTER:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
+				"command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
+		PktCmdP->SubCommand = RIOC_READ_REGISTER;
+		PktCmdP->SubAddr = SubCmd.Addr;
+		break;
+	case RIOC_RESUME:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
+				CmdBlkP);
+		break;
+	case RIOC_RFLUSH:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
+				CmdBlkP);
+		CmdBlkP->PostFuncP = RIORFlushEnable;
+		break;
+	case RIOC_SUSPEND:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
+				CmdBlkP);
+		break;
+
+	case RIOC_MGET:
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
+				CmdBlkP);
+		break;
+
+	case RIOC_MSET:
+	case RIOC_MBIC:
+	case RIOC_MBIS:
+		CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
+		rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
+				"blk %p\n", CmdBlkP);
+		break;
+
+	case RIOC_WFLUSH:
+		/*
+		 ** If we have queued up the maximum number of Write flushes
+		 ** allowed then we should not bother sending any more to the
+		 ** RTA.
+		 */
+		if (PortP->WflushFlag == (typeof(PortP->WflushFlag))-1) {
+			rio_dprintk(RIO_DEBUG_CTRL, "Trashed WFLUSH, "
+					"WflushFlag about to wrap!");
+			RIOFreeCmdBlk(CmdBlkP);
+			return (RIO_FAIL);
+		} else {
+			rio_dprintk(RIO_DEBUG_CTRL, "Queue WFLUSH command "
+					"blk %p\n", CmdBlkP);
+			CmdBlkP->PostFuncP = RIOWFlushMark;
+		}
+		break;
+	}
+
+	PortP->InUse++;
+
+	Ret = RIOQueueCmdBlk(PortP->HostP, rup, CmdBlkP);
+
+	return Ret;
+}
diff --git a/drivers/staging/generic_serial/rio/riodrvr.h b/drivers/staging/generic_serial/rio/riodrvr.h
new file mode 100644
index 0000000..0907e71
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riodrvr.h
@@ -0,0 +1,138 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riodrvr.h
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 09:22:46
+**	Retrieved	: 11/6/98 09:22:46
+**
+**  ident @(#)riodrvr.h	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __riodrvr_h
+#define __riodrvr_h
+
+#include <asm/param.h>		/* for HZ */
+
+#define MEMDUMP_SIZE	32
+#define	MOD_DISABLE	(RIO_NOREAD|RIO_NOWRITE|RIO_NOXPRINT)
+
+
+struct rio_info {
+	int mode;		/* Intr or polled, word/byte */
+	spinlock_t RIOIntrSem;	/* Interrupt thread sem */
+	int current_chan;	/* current channel */
+	int RIOFailed;		/* Not initialised ? */
+	int RIOInstallAttempts;	/* no. of rio-install() calls */
+	int RIOLastPCISearch;	/* status of last search */
+	int RIONumHosts;	/* Number of RIO Hosts */
+	struct Host *RIOHosts;	/* RIO Host values */
+	struct Port **RIOPortp;	/* RIO port values */
+/*
+** 02.03.1999 ARG - ESIL 0820 fix
+** We no longer use RIOBootMode
+**
+	int			RIOBootMode;		* RIO boot mode *
+**
+*/
+	int RIOPrintDisabled;	/* RIO printing disabled ? */
+	int RIOPrintLogState;	/* RIO printing state ? */
+	int RIOPolling;		/* Polling ? */
+/*
+** 09.12.1998 ARG - ESIL 0776 part fix
+** The 'RIO_QUICK_CHECK' ioctl was using RIOHalted.
+** The fix for this ESIL introduces another member (RIORtaDisCons) here to be
+** updated in RIOConCon() - to keep track of RTA connections/disconnections.
+** 'RIO_QUICK_CHECK' now returns the value of RIORtaDisCons.
+*/
+	int RIOHalted;		/* halted ? */
+	int RIORtaDisCons;	/* RTA connections/disconnections */
+	unsigned int RIOReadCheck;	/* Rio read check */
+	unsigned int RIONoMessage;	/* To display message or not */
+	unsigned int RIONumBootPkts;	/* how many packets for an RTA */
+	unsigned int RIOBootCount;	/* size of RTA code */
+	unsigned int RIOBooting;	/* count of outstanding boots */
+	unsigned int RIOSystemUp;	/* Booted ?? */
+	unsigned int RIOCounting;	/* for counting interrupts */
+	unsigned int RIOIntCount;	/* # of intr since last check */
+	unsigned int RIOTxCount;	/* number of xmit intrs  */
+	unsigned int RIORxCount;	/* number of rx intrs */
+	unsigned int RIORupCount;	/* number of rup intrs */
+	int RIXTimer;
+	int RIOBufferSize;	/* Buffersize */
+	int RIOBufferMask;	/* Buffersize */
+
+	int RIOFirstMajor;	/* First host card's major no */
+
+	unsigned int RIOLastPortsMapped;	/* highest port number known */
+	unsigned int RIOFirstPortsMapped;	/* lowest port number known */
+
+	unsigned int RIOLastPortsBooted;	/* highest port number running */
+	unsigned int RIOFirstPortsBooted;	/* lowest port number running */
+
+	unsigned int RIOLastPortsOpened;	/* highest port number running */
+	unsigned int RIOFirstPortsOpened;	/* lowest port number running */
+
+	/* Flag to say that the topology information has been changed. */
+	unsigned int RIOQuickCheck;
+	unsigned int CdRegister;	/* ??? */
+	int RIOSignalProcess;	/* Signalling process */
+	int rio_debug;		/* To debug ... */
+	int RIODebugWait;	/* For what ??? */
+	int tpri;		/* Thread prio */
+	int tid;		/* Thread id */
+	unsigned int _RIO_Polled;	/* Counter for polling */
+	unsigned int _RIO_Interrupted;	/* Counter for interrupt */
+	int intr_tid;		/* iointset return value */
+	int TxEnSem;		/* TxEnable Semaphore */
+
+
+	struct Error RIOError;	/* to Identify what went wrong */
+	struct Conf RIOConf;	/* Configuration ??? */
+	struct ttystatics channel[RIO_PORTS];	/* channel information */
+	char RIOBootPackets[1 + (SIXTY_FOUR_K / RTA_BOOT_DATA_SIZE)]
+	    [RTA_BOOT_DATA_SIZE];
+	struct Map RIOConnectTable[TOTAL_MAP_ENTRIES];
+	struct Map RIOSavedTable[TOTAL_MAP_ENTRIES];
+
+	/* RTA to host binding table for master/slave operation */
+	unsigned long RIOBindTab[MAX_RTA_BINDINGS];
+	/* RTA memory dump variable */
+	unsigned char RIOMemDump[MEMDUMP_SIZE];
+	struct ModuleInfo RIOModuleTypes[MAX_MODULE_TYPES];
+
+};
+
+
+#ifdef linux
+#define debug(x)        printk x
+#else
+#define debug(x)	kkprintf x
+#endif
+
+
+
+#define RIO_RESET_INT	0x7d80
+
+#endif				/* __riodrvr.h */
diff --git a/drivers/staging/generic_serial/rio/rioinfo.h b/drivers/staging/generic_serial/rio/rioinfo.h
new file mode 100644
index 0000000..42ff1e7
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioinfo.h
@@ -0,0 +1,92 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioinfo.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 14:07:49
+**	Retrieved	: 11/6/98 14:07:50
+**
+**  ident @(#)rioinfo.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rioinfo_h
+#define __rioinfo_h
+
+/*
+** Host card data structure
+*/
+struct RioHostInfo {
+	long location;		/* RIO Card Base I/O address */
+	long vector;		/* RIO Card IRQ vector */
+	int bus;		/* ISA/EISA/MCA/PCI */
+	int mode;		/* pointer to host mode - INTERRUPT / POLLED */
+	struct old_sgttyb
+	*Sg;			/* pointer to default term characteristics */
+};
+
+
+/* Mode in rio device info */
+#define INTERRUPTED_MODE	0x01	/* Interrupt is generated */
+#define POLLED_MODE		0x02	/* No interrupt */
+#define AUTO_MODE		0x03	/* Auto mode */
+
+#define WORD_ACCESS_MODE	0x10	/* Word Access Mode */
+#define BYTE_ACCESS_MODE	0x20	/* Byte Access Mode */
+
+
+/* Bus type that RIO supports */
+#define ISA_BUS			0x01	/* The card is ISA */
+#define EISA_BUS		0x02	/* The card is EISA */
+#define MCA_BUS			0x04	/* The card is MCA */
+#define PCI_BUS			0x08	/* The card is PCI */
+
+/*
+** 11.11.1998 ARG - ESIL ???? part fix
+** Moved definition for 'CHAN' here from rioinfo.c (it is now
+** called 'DEF_TERM_CHARACTERISTICS').
+*/
+
+#define DEF_TERM_CHARACTERISTICS \
+{ \
+	B19200, B19200,				/* input and output speed */ \
+	'H' - '@',				/* erase char */ \
+	-1,					/* 2nd erase char */ \
+	'U' - '@',				/* kill char */ \
+	ECHO | CRMOD,				/* mode */ \
+	'C' - '@',				/* interrupt character */ \
+	'\\' - '@',				/* quit char */ \
+	'Q' - '@',				/* start char */ \
+	'S' - '@',				/* stop char */ \
+	'D' - '@',				/* EOF */ \
+	-1,					/* brk */ \
+	(LCRTBS | LCRTERA | LCRTKIL | LCTLECH),	/* local mode word */ \
+	'Z' - '@',				/* process stop */ \
+	'Y' - '@',				/* delayed stop */ \
+	'R' - '@',				/* reprint line */ \
+	'O' - '@',				/* flush output */ \
+	'W' - '@',				/* word erase */ \
+	'V' - '@'				/* literal next char */ \
+}
+
+#endif				/* __rioinfo_h */
diff --git a/drivers/staging/generic_serial/rio/rioinit.c b/drivers/staging/generic_serial/rio/rioinit.c
new file mode 100644
index 0000000..24a282b
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioinit.c
@@ -0,0 +1,421 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioinit.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:43
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)rioinit.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "rio_linux.h"
+
+int RIOPCIinit(struct rio_info *p, int Mode);
+
+static int RIOScrub(int, u8 __iomem *, int);
+
+
+/**
+** RIOAssignAT :
+**
+** Fill out the fields in the p->RIOHosts structure now we know we know
+** we have a board present.
+**
+** bits < 0 indicates 8 bit operation requested,
+** bits > 0 indicates 16 bit operation.
+*/
+
+int RIOAssignAT(struct rio_info *p, int	Base, void __iomem *virtAddr, int mode)
+{
+	int		bits;
+	struct DpRam __iomem *cardp = (struct DpRam __iomem *)virtAddr;
+
+	if ((Base < ONE_MEG) || (mode & BYTE_ACCESS_MODE))
+		bits = BYTE_OPERATION;
+	else
+		bits = WORD_OPERATION;
+
+	/*
+	** Board has passed its scrub test. Fill in all the
+	** transient stuff.
+	*/
+	p->RIOHosts[p->RIONumHosts].Caddr	= virtAddr;
+	p->RIOHosts[p->RIONumHosts].CardP	= virtAddr;
+
+	/*
+	** Revision 01 AT host cards don't support WORD operations,
+	*/
+	if (readb(&cardp->DpRevision) == 01)
+		bits = BYTE_OPERATION;
+
+	p->RIOHosts[p->RIONumHosts].Type = RIO_AT;
+	p->RIOHosts[p->RIONumHosts].Copy = rio_copy_to_card;
+											/* set this later */
+	p->RIOHosts[p->RIONumHosts].Slot = -1;
+	p->RIOHosts[p->RIONumHosts].Mode = SLOW_LINKS | SLOW_AT_BUS | bits;
+	writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | p->RIOHosts[p->RIONumHosts].Mode | INTERRUPT_DISABLE ,
+		&p->RIOHosts[p->RIONumHosts].Control);
+	writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+	writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | p->RIOHosts[p->RIONumHosts].Mode | INTERRUPT_DISABLE,
+		&p->RIOHosts[p->RIONumHosts].Control);
+	writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
+	p->RIOHosts[p->RIONumHosts].UniqueNum =
+		((readb(&p->RIOHosts[p->RIONumHosts].Unique[0])&0xFF)<<0)|
+		((readb(&p->RIOHosts[p->RIONumHosts].Unique[1])&0xFF)<<8)|
+		((readb(&p->RIOHosts[p->RIONumHosts].Unique[2])&0xFF)<<16)|
+		((readb(&p->RIOHosts[p->RIONumHosts].Unique[3])&0xFF)<<24);
+	rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Uniquenum 0x%x\n",p->RIOHosts[p->RIONumHosts].UniqueNum);
+
+	p->RIONumHosts++;
+	rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Tests Passed at 0x%x\n", Base);
+	return(1);
+}
+
+static	u8	val[] = {
+#ifdef VERY_LONG_TEST
+	  0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+	  0xa5, 0xff, 0x5a, 0x00, 0xff, 0xc9, 0x36, 
+#endif
+	  0xff, 0x00, 0x00 };
+
+#define	TEST_END sizeof(val)
+
+/*
+** RAM test a board. 
+** Nothing too complicated, just enough to check it out.
+*/
+int RIOBoardTest(unsigned long paddr, void __iomem *caddr, unsigned char type, int slot)
+{
+	struct DpRam __iomem *DpRam = caddr;
+	void __iomem *ram[4];
+	int  size[4];
+	int  op, bank;
+	int  nbanks;
+
+	rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Reset host type=%d, DpRam=%p, slot=%d\n",
+			type, DpRam, slot);
+
+	RIOHostReset(type, DpRam, slot);
+
+	/*
+	** Scrub the memory. This comes in several banks:
+	** DPsram1	- 7000h bytes
+	** DPsram2	- 200h  bytes
+	** DPsram3	- 7000h bytes
+	** scratch	- 1000h bytes
+	*/
+
+	rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Setup ram/size arrays\n");
+
+	size[0] = DP_SRAM1_SIZE;
+	size[1] = DP_SRAM2_SIZE;
+	size[2] = DP_SRAM3_SIZE;
+	size[3] = DP_SCRATCH_SIZE;
+
+	ram[0] = DpRam->DpSram1;
+	ram[1] = DpRam->DpSram2;
+	ram[2] = DpRam->DpSram3;
+	nbanks = (type == RIO_PCI) ? 3 : 4;
+	if (nbanks == 4)
+		ram[3] = DpRam->DpScratch;
+
+
+	if (nbanks == 3) {
+		rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Memory: %p(0x%x), %p(0x%x), %p(0x%x)\n",
+				ram[0], size[0], ram[1], size[1], ram[2], size[2]);
+	} else {
+		rio_dprintk (RIO_DEBUG_INIT, "RIO-init: %p(0x%x), %p(0x%x), %p(0x%x), %p(0x%x)\n",
+				ram[0], size[0], ram[1], size[1], ram[2], size[2], ram[3], size[3]);
+	}
+
+	/*
+	** This scrub operation will test for crosstalk between
+	** banks. TEST_END is a magic number, and relates to the offset
+	** within the 'val' array used by Scrub.
+	*/
+	for (op=0; op<TEST_END; op++) {
+		for (bank=0; bank<nbanks; bank++) {
+			if (RIOScrub(op, ram[bank], size[bank]) == RIO_FAIL) {
+				rio_dprintk (RIO_DEBUG_INIT, "RIO-init: RIOScrub band %d, op %d failed\n", 
+							bank, op);
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	rio_dprintk (RIO_DEBUG_INIT, "Test completed\n");
+	return 0;
+}
+
+
+/*
+** Scrub an area of RAM.
+** Define PRETEST and POSTTEST for a more thorough checking of the
+** state of the memory.
+** Call with op set to an index into the above 'val' array to determine
+** which value will be written into memory.
+** Call with op set to zero means that the RAM will not be read and checked
+** before it is written.
+** Call with op not zero and the RAM will be read and compared with val[op-1]
+** to check that the data from the previous phase was retained.
+*/
+
+static int RIOScrub(int op, u8 __iomem *ram, int size)
+{
+	int off;
+	unsigned char	oldbyte;
+	unsigned char	newbyte;
+	unsigned char	invbyte;
+	unsigned short	oldword;
+	unsigned short	newword;
+	unsigned short	invword;
+	unsigned short	swapword;
+
+	if (op) {
+		oldbyte = val[op-1];
+		oldword = oldbyte | (oldbyte<<8);
+	} else
+	  oldbyte = oldword = 0; /* Tell the compiler we've initilalized them. */
+	newbyte = val[op];
+	newword = newbyte | (newbyte<<8);
+	invbyte = ~newbyte;
+	invword = invbyte | (invbyte<<8);
+
+	/*
+	** Check that the RAM contains the value that should have been left there
+	** by the previous test (not applicable for pass zero)
+	*/
+	if (op) {
+		for (off=0; off<size; off++) {
+			if (readb(ram + off) != oldbyte) {
+				rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 1: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, readb(ram + off));
+				return RIO_FAIL;
+			}
+		}
+		for (off=0; off<size; off+=2) {
+			if (readw(ram + off) != oldword) {
+				rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: WORD at offset 0x%x should have been=%x, was=%x\n",off,oldword, readw(ram + off));
+				rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Pre Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram+off+1));
+				return RIO_FAIL;
+			}
+		}
+	}
+
+	/*
+	** Now write the INVERSE of the test data into every location, using
+	** BYTE write operations, first checking before each byte is written
+	** that the location contains the old value still, and checking after
+	** the write that the location contains the data specified - this is
+	** the BYTE read/write test.
+	*/
+	for (off=0; off<size; off++) {
+		if (op && (readb(ram + off) != oldbyte)) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Pre Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, oldbyte, readb(ram + off));
+			return RIO_FAIL;
+		}
+		writeb(invbyte, ram + off);
+		if (readb(ram + off) != invbyte) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Byte Inv Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, invbyte, readb(ram + off));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now, use WORD operations to write the test value into every location,
+	** check as before that the location contains the previous test value
+	** before overwriting, and that it contains the data value written
+	** afterwards.
+	** This is the WORD operation test.
+	*/
+	for (off=0; off<size; off+=2) {
+		if (readw(ram + off) != invword) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: WORD at offset 0x%x should have been=%x, was=%x\n", off, invword, readw(ram + off));
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Word Inv Check: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram+off+1));
+			return RIO_FAIL;
+		}
+
+		writew(newword, ram + off);
+		if ( readw(ram + off) != newword ) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, readw(ram + off));
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** now run through the block of memory again, first in byte mode
+	** then in word mode, and check that all the locations contain the
+	** required test data.
+	*/
+	for (off=0; off<size; off++) {
+		if (readb(ram + off) != newbyte) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Byte Check: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, readb(ram + off));
+			return RIO_FAIL;
+		}
+	}
+
+	for (off=0; off<size; off+=2) {
+		if (readw(ram + off) != newword ) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: WORD at offset 0x%x should have been=%x, was=%x\n", off, newword, readw(ram + off));
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: Post Word Check 2: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+			return RIO_FAIL;
+		}
+	}
+
+	/*
+	** time to check out byte swapping errors
+	*/
+	swapword = invbyte | (newbyte << 8);
+
+	for (off=0; off<size; off+=2) {
+		writeb(invbyte, &ram[off]);
+		writeb(newbyte, &ram[off+1]);
+	}
+
+	for ( off=0; off<size; off+=2 ) {
+		if (readw(ram + off) != swapword) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: WORD at offset 0x%x should have been=%x, was=%x\n", off, swapword, readw(ram + off));
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 1: BYTE at offset 0x%x is %x BYTE at offset 0x%x is %x\n", off, readb(ram + off), off+1, readb(ram + off + 1));
+			return RIO_FAIL;
+		}
+		writew(~swapword, ram + off);
+	}
+
+	for (off=0; off<size; off+=2) {
+		if (readb(ram + off) != newbyte) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off, newbyte, readb(ram + off));
+			return RIO_FAIL;
+		}
+		if (readb(ram + off + 1) != invbyte) {
+			rio_dprintk (RIO_DEBUG_INIT, "RIO-init: SwapWord Check 2: BYTE at offset 0x%x should have been=%x, was=%x\n", off+1, invbyte, readb(ram + off + 1));
+			return RIO_FAIL;
+		}
+		writew(newword, ram + off);
+	}
+	return 0;
+}
+
+
+int RIODefaultName(struct rio_info *p, struct Host *HostP, unsigned int	UnitId)
+{
+	memcpy(HostP->Mapping[UnitId].Name, "UNKNOWN RTA X-XX", 17);
+	HostP->Mapping[UnitId].Name[12]='1'+(HostP-p->RIOHosts);
+	if ((UnitId+1) > 9) {
+		HostP->Mapping[UnitId].Name[14]='0'+((UnitId+1)/10);
+		HostP->Mapping[UnitId].Name[15]='0'+((UnitId+1)%10);
+	}
+	else {
+		HostP->Mapping[UnitId].Name[14]='1'+UnitId;
+		HostP->Mapping[UnitId].Name[15]=0;
+	}
+	return 0;
+}
+
+#define RIO_RELEASE	"Linux"
+#define RELEASE_ID	"1.0"
+
+static struct rioVersion	stVersion;
+
+struct rioVersion *RIOVersid(void)
+{
+    strlcpy(stVersion.version, "RIO driver for linux V1.0",
+	    sizeof(stVersion.version));
+    strlcpy(stVersion.buildDate, __DATE__,
+	    sizeof(stVersion.buildDate));
+
+    return &stVersion;
+}
+
+void RIOHostReset(unsigned int Type, struct DpRam __iomem *DpRamP, unsigned int Slot)
+{
+	/*
+	** Reset the Tpu
+	*/
+	rio_dprintk (RIO_DEBUG_INIT,  "RIOHostReset: type 0x%x", Type);
+	switch ( Type ) {
+	case RIO_AT:
+		rio_dprintk (RIO_DEBUG_INIT, " (RIO_AT)\n");
+		writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION |
+			SLOW_LINKS | SLOW_AT_BUS, &DpRamP->DpControl);
+		writeb(0xFF, &DpRamP->DpResetTpu);
+		udelay(3);
+			rio_dprintk (RIO_DEBUG_INIT,  "RIOHostReset: Don't know if it worked. Try reset again\n");
+		writeb(BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE |
+			BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS, &DpRamP->DpControl);
+		writeb(0xFF, &DpRamP->DpResetTpu);
+		udelay(3);
+		break;
+	case RIO_PCI:
+		rio_dprintk (RIO_DEBUG_INIT, " (RIO_PCI)\n");
+		writeb(RIO_PCI_BOOT_FROM_RAM, &DpRamP->DpControl);
+		writeb(0xFF, &DpRamP->DpResetInt);
+		writeb(0xFF, &DpRamP->DpResetTpu);
+		udelay(100);
+		break;
+	default:
+		rio_dprintk (RIO_DEBUG_INIT, " (UNKNOWN)\n");
+		break;
+	}
+	return;
+}
diff --git a/drivers/staging/generic_serial/rio/riointr.c b/drivers/staging/generic_serial/rio/riointr.c
new file mode 100644
index 0000000..2e71aeca
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riointr.c
@@ -0,0 +1,645 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riointr.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:44
+**	Retrieved	: 11/6/98 10:33:49
+**
+**  ident @(#)riointr.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+#include <linux/delay.h>
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+
+
+static void RIOReceive(struct rio_info *, struct Port *);
+
+
+static char *firstchars(char *p, int nch)
+{
+	static char buf[2][128];
+	static int t = 0;
+	t = !t;
+	memcpy(buf[t], p, nch);
+	buf[t][nch] = 0;
+	return buf[t];
+}
+
+
+#define	INCR( P, I )	((P) = (((P)+(I)) & p->RIOBufferMask))
+/* Enable and start the transmission of packets */
+void RIOTxEnable(char *en)
+{
+	struct Port *PortP;
+	struct rio_info *p;
+	struct tty_struct *tty;
+	int c;
+	struct PKT __iomem *PacketP;
+	unsigned long flags;
+
+	PortP = (struct Port *) en;
+	p = (struct rio_info *) PortP->p;
+	tty = PortP->gs.port.tty;
+
+
+	rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt);
+
+	if (!PortP->gs.xmit_cnt)
+		return;
+
+
+	/* This routine is an order of magnitude simpler than the specialix
+	   version. One of the disadvantages is that this version will send
+	   an incomplete packet (usually 64 bytes instead of 72) once for
+	   every 4k worth of data. Let's just say that this won't influence
+	   performance significantly..... */
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	while (can_add_transmit(&PacketP, PortP)) {
+		c = PortP->gs.xmit_cnt;
+		if (c > PKT_MAX_DATA_LEN)
+			c = PKT_MAX_DATA_LEN;
+
+		/* Don't copy past the end of the source buffer */
+		if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail)
+			c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;
+
+		{
+			int t;
+			t = (c > 10) ? 10 : c;
+
+			rio_dprintk(RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", PortP->PortNum, c, firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail, t), firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail + c - t, t));
+		}
+		/* If for one reason or another, we can't copy more data,
+		   we're done! */
+		if (c == 0)
+			break;
+
+		rio_memcpy_toio(PortP->HostP->Caddr, PacketP->data, PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
+		/*    udelay (1); */
+
+		writeb(c, &(PacketP->len));
+		if (!(PortP->State & RIO_DELETED)) {
+			add_transmit(PortP);
+			/*
+			 ** Count chars tx'd for port statistics reporting
+			 */
+			if (PortP->statsGather)
+				PortP->txchars += c;
+		}
+		PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE - 1);
+		PortP->gs.xmit_cnt -= c;
+	}
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN))
+		tty_wakeup(PortP->gs.port.tty);
+
+}
+
+
+/*
+** RIO Host Service routine. Does all the work traditionally associated with an
+** interrupt.
+*/
+static int RupIntr;
+static int RxIntr;
+static int TxIntr;
+
+void RIOServiceHost(struct rio_info *p, struct Host *HostP)
+{
+	rio_spin_lock(&HostP->HostLock);
+	if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+		static int t = 0;
+		rio_spin_unlock(&HostP->HostLock);
+		if ((t++ % 200) == 0)
+			rio_dprintk(RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int) HostP->Flags);
+		return;
+	}
+	rio_spin_unlock(&HostP->HostLock);
+
+	if (readw(&HostP->ParmMapP->rup_intr)) {
+		writew(0, &HostP->ParmMapP->rup_intr);
+		p->RIORupCount++;
+		RupIntr++;
+		rio_dprintk(RIO_DEBUG_INTR, "rio: RUP interrupt on host %Zd\n", HostP - p->RIOHosts);
+		RIOPollHostCommands(p, HostP);
+	}
+
+	if (readw(&HostP->ParmMapP->rx_intr)) {
+		int port;
+
+		writew(0, &HostP->ParmMapP->rx_intr);
+		p->RIORxCount++;
+		RxIntr++;
+
+		rio_dprintk(RIO_DEBUG_INTR, "rio: RX interrupt on host %Zd\n", HostP - p->RIOHosts);
+		/*
+		 ** Loop through every port. If the port is mapped into
+		 ** the system ( i.e. has /dev/ttyXXXX associated ) then it is
+		 ** worth checking. If the port isn't open, grab any packets
+		 ** hanging on its receive queue and stuff them on the free
+		 ** list; check for commands on the way.
+		 */
+		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
+			struct Port *PortP = p->RIOPortp[port];
+			struct tty_struct *ttyP;
+			struct PKT __iomem *PacketP;
+
+			/*
+			 ** not mapped in - most of the RIOPortp[] information
+			 ** has not been set up!
+			 ** Optimise: ports come in bundles of eight.
+			 */
+			if (!PortP->Mapped) {
+				port += 7;
+				continue;	/* with the next port */
+			}
+
+			/*
+			 ** If the host board isn't THIS host board, check the next one.
+			 ** optimise: ports come in bundles of eight.
+			 */
+			if (PortP->HostP != HostP) {
+				port += 7;
+				continue;
+			}
+
+			/*
+			 ** Let us see - is the port open? If not, then don't service it.
+			 */
+			if (!(PortP->PortState & PORT_ISOPEN)) {
+				continue;
+			}
+
+			/*
+			 ** find corresponding tty structure. The process of mapping
+			 ** the ports puts these here.
+			 */
+			ttyP = PortP->gs.port.tty;
+
+			/*
+			 ** Lock the port before we begin working on it.
+			 */
+			rio_spin_lock(&PortP->portSem);
+
+			/*
+			 ** Process received data if there is any.
+			 */
+			if (can_remove_receive(&PacketP, PortP))
+				RIOReceive(p, PortP);
+
+			/*
+			 ** If there is no data left to be read from the port, and
+			 ** it's handshake bit is set, then we must clear the handshake,
+			 ** so that that downstream RTA is re-enabled.
+			 */
+			if (!can_remove_receive(&PacketP, PortP) && (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET)) {
+				/*
+				 ** MAGIC! ( Basically, handshake the RX buffer, so that
+				 ** the RTAs upstream can be re-enabled. )
+				 */
+				rio_dprintk(RIO_DEBUG_INTR, "Set RX handshake bit\n");
+				writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);
+			}
+			rio_spin_unlock(&PortP->portSem);
+		}
+	}
+
+	if (readw(&HostP->ParmMapP->tx_intr)) {
+		int port;
+
+		writew(0, &HostP->ParmMapP->tx_intr);
+
+		p->RIOTxCount++;
+		TxIntr++;
+		rio_dprintk(RIO_DEBUG_INTR, "rio: TX interrupt on host %Zd\n", HostP - p->RIOHosts);
+
+		/*
+		 ** Loop through every port.
+		 ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX
+		 ** associated ) then it is worth checking.
+		 */
+		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
+			struct Port *PortP = p->RIOPortp[port];
+			struct tty_struct *ttyP;
+			struct PKT __iomem *PacketP;
+
+			/*
+			 ** not mapped in - most of the RIOPortp[] information
+			 ** has not been set up!
+			 */
+			if (!PortP->Mapped) {
+				port += 7;
+				continue;	/* with the next port */
+			}
+
+			/*
+			 ** If the host board isn't running, then its data structures
+			 ** are no use to us - continue quietly.
+			 */
+			if (PortP->HostP != HostP) {
+				port += 7;
+				continue;	/* with the next port */
+			}
+
+			/*
+			 ** Let us see - is the port open? If not, then don't service it.
+			 */
+			if (!(PortP->PortState & PORT_ISOPEN)) {
+				continue;
+			}
+
+			rio_dprintk(RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port);
+			/*
+			 ** Lock the port before we begin working on it.
+			 */
+			rio_spin_lock(&PortP->portSem);
+
+			/*
+			 ** If we can't add anything to the transmit queue, then
+			 ** we need do none of this processing.
+			 */
+			if (!can_add_transmit(&PacketP, PortP)) {
+				rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n");
+				rio_spin_unlock(&PortP->portSem);
+				continue;
+			}
+
+			/*
+			 ** find corresponding tty structure. The process of mapping
+			 ** the ports puts these here.
+			 */
+			ttyP = PortP->gs.port.tty;
+			/* If ttyP is NULL, the port is getting closed. Forget about it. */
+			if (!ttyP) {
+				rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n");
+				rio_spin_unlock(&PortP->portSem);
+				continue;
+			}
+			/*
+			 ** If there is more room available we start up the transmit
+			 ** data process again. This can be direct I/O, if the cookmode
+			 ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the
+			 ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch
+			 ** characters via the line discipline. We must always call
+			 ** the line discipline,
+			 ** so that user input characters can be echoed correctly.
+			 **
+			 ** ++++ Update +++++
+			 ** With the advent of double buffering, we now see if
+			 ** TxBufferOut-In is non-zero. If so, then we copy a packet
+			 ** to the output place, and set it going. If this empties
+			 ** the buffer, then we must issue a wakeup( ) on OUT.
+			 ** If it frees space in the buffer then we must issue
+			 ** a wakeup( ) on IN.
+			 **
+			 ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we
+			 ** have to send a WFLUSH command down the PHB, to mark the
+			 ** end point of a WFLUSH. We also need to clear out any
+			 ** data from the double buffer! ( note that WflushFlag is a
+			 ** *count* of the number of WFLUSH commands outstanding! )
+			 **
+			 ** ++++ And there's more!
+			 ** If an RTA is powered off, then on again, and rebooted,
+			 ** whilst it has ports open, then we need to re-open the ports.
+			 ** ( reasonable enough ). We can't do this when we spot the
+			 ** re-boot, in interrupt time, because the queue is probably
+			 ** full. So, when we come in here, we need to test if any
+			 ** ports are in this condition, and re-open the port before
+			 ** we try to send any more data to it. Now, the re-booted
+			 ** RTA will be discarding packets from the PHB until it
+			 ** receives this open packet, but don't worry tooo much
+			 ** about that. The one thing that is interesting is the
+			 ** combination of this effect and the WFLUSH effect!
+			 */
+			/* For now don't handle RTA reboots. -- REW.
+			   Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */
+			if (PortP->MagicFlags) {
+				if (PortP->MagicFlags & MAGIC_REBOOT) {
+					/*
+					 ** well, the RTA has been rebooted, and there is room
+					 ** on its queue to add the open packet that is required.
+					 **
+					 ** The messy part of this line is trying to decide if
+					 ** we need to call the Param function as a tty or as
+					 ** a modem.
+					 ** DONT USE CLOCAL AS A TEST FOR THIS!
+					 **
+					 ** If we can't param the port, then move on to the
+					 ** next port.
+					 */
+					PortP->InUse = NOT_INUSE;
+
+					rio_spin_unlock(&PortP->portSem);
+					if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL)
+						continue;	/* with next port */
+					rio_spin_lock(&PortP->portSem);
+					PortP->MagicFlags &= ~MAGIC_REBOOT;
+				}
+
+				/*
+				 ** As mentioned above, this is a tacky hack to cope
+				 ** with WFLUSH
+				 */
+				if (PortP->WflushFlag) {
+					rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n");
+
+					if (PortP->InUse)
+						rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n");
+				}
+
+				while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) {
+					int p;
+					struct PktCmd __iomem *PktCmdP;
+
+					rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n");
+					/*
+					 ** make it look just like a WFLUSH command
+					 */
+					PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];
+
+					writeb(RIOC_WFLUSH, &PktCmdP->Command);
+
+					p = PortP->HostPort % (u16) PORTS_PER_RTA;
+
+					/*
+					 ** If second block of ports for 16 port RTA, add 8
+					 ** to index 8-15.
+					 */
+					if (PortP->SecondBlock)
+						p += PORTS_PER_RTA;
+
+					writeb(p, &PktCmdP->PhbNum);
+
+					/*
+					 ** to make debuggery easier
+					 */
+					writeb('W', &PacketP->data[2]);
+					writeb('F', &PacketP->data[3]);
+					writeb('L', &PacketP->data[4]);
+					writeb('U', &PacketP->data[5]);
+					writeb('S', &PacketP->data[6]);
+					writeb('H', &PacketP->data[7]);
+					writeb(' ', &PacketP->data[8]);
+					writeb('0' + PortP->WflushFlag, &PacketP->data[9]);
+					writeb(' ', &PacketP->data[10]);
+					writeb(' ', &PacketP->data[11]);
+					writeb('\0', &PacketP->data[12]);
+
+					/*
+					 ** its two bytes long!
+					 */
+					writeb(PKT_CMD_BIT | 2, &PacketP->len);
+
+					/*
+					 ** queue it!
+					 */
+					if (!(PortP->State & RIO_DELETED)) {
+						add_transmit(PortP);
+						/*
+						 ** Count chars tx'd for port statistics reporting
+						 */
+						if (PortP->statsGather)
+							PortP->txchars += 2;
+					}
+
+					if (--(PortP->WflushFlag) == 0) {
+						PortP->MagicFlags &= ~MAGIC_FLUSH;
+					}
+
+					rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag);
+				}
+				if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) {
+					if (PortP->MagicFlags & MAGIC_FLUSH) {
+						PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
+					} else {
+						if (!can_add_transmit(&PacketP, PortP)) {
+							rio_spin_unlock(&PortP->portSem);
+							continue;
+						}
+						rio_spin_unlock(&PortP->portSem);
+						RIOTxEnable((char *) PortP);
+						rio_spin_lock(&PortP->portSem);
+						PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
+					}
+				}
+			}
+
+
+			/*
+			 ** If we can't add anything to the transmit queue, then
+			 ** we need do none of the remaining processing.
+			 */
+			if (!can_add_transmit(&PacketP, PortP)) {
+				rio_spin_unlock(&PortP->portSem);
+				continue;
+			}
+
+			rio_spin_unlock(&PortP->portSem);
+			RIOTxEnable((char *) PortP);
+		}
+	}
+}
+
+/*
+** Routine for handling received data for tty drivers
+*/
+static void RIOReceive(struct rio_info *p, struct Port *PortP)
+{
+	struct tty_struct *TtyP;
+	unsigned short transCount;
+	struct PKT __iomem *PacketP;
+	register unsigned int DataCnt;
+	unsigned char __iomem *ptr;
+	unsigned char *buf;
+	int copied = 0;
+
+	static int intCount, RxIntCnt;
+
+	/*
+	 ** The receive data process is to remove packets from the
+	 ** PHB until there aren't any more or the current cblock
+	 ** is full. When this occurs, there will be some left over
+	 ** data in the packet, that we must do something with.
+	 ** As we haven't unhooked the packet from the read list
+	 ** yet, we can just leave the packet there, having first
+	 ** made a note of how far we got. This means that we need
+	 ** a pointer per port saying where we start taking the
+	 ** data from - this will normally be zero, but when we
+	 ** run out of space it will be set to the offset of the
+	 ** next byte to copy from the packet data area. The packet
+	 ** length field is decremented by the number of bytes that
+	 ** we successfully removed from the packet. When this reaches
+	 ** zero, we reset the offset pointer to be zero, and free
+	 ** the packet from the front of the queue.
+	 */
+
+	intCount++;
+
+	TtyP = PortP->gs.port.tty;
+	if (!TtyP) {
+		rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: tty is null. \n");
+		return;
+	}
+
+	if (PortP->State & RIO_THROTTLE_RX) {
+		rio_dprintk(RIO_DEBUG_INTR, "RIOReceive: Throttled. Can't handle more input.\n");
+		return;
+	}
+
+	if (PortP->State & RIO_DELETED) {
+		while (can_remove_receive(&PacketP, PortP)) {
+			remove_receive(PortP);
+			put_free_end(PortP->HostP, PacketP);
+		}
+	} else {
+		/*
+		 ** loop, just so long as:
+		 **   i ) there's some data ( i.e. can_remove_receive )
+		 **  ii ) we haven't been blocked
+		 ** iii ) there's somewhere to put the data
+		 **  iv ) we haven't outstayed our welcome
+		 */
+		transCount = 1;
+		while (can_remove_receive(&PacketP, PortP)
+		       && transCount) {
+			RxIntCnt++;
+
+			/*
+			 ** check that it is not a command!
+			 */
+			if (readb(&PacketP->len) & PKT_CMD_BIT) {
+				rio_dprintk(RIO_DEBUG_INTR, "RIO: unexpected command packet received on PHB\n");
+				/*      rio_dprint(RIO_DEBUG_INTR, (" sysport   = %d\n", p->RIOPortp->PortNum)); */
+				rio_dprintk(RIO_DEBUG_INTR, " dest_unit = %d\n", readb(&PacketP->dest_unit));
+				rio_dprintk(RIO_DEBUG_INTR, " dest_port = %d\n", readb(&PacketP->dest_port));
+				rio_dprintk(RIO_DEBUG_INTR, " src_unit  = %d\n", readb(&PacketP->src_unit));
+				rio_dprintk(RIO_DEBUG_INTR, " src_port  = %d\n", readb(&PacketP->src_port));
+				rio_dprintk(RIO_DEBUG_INTR, " len	   = %d\n", readb(&PacketP->len));
+				rio_dprintk(RIO_DEBUG_INTR, " control   = %d\n", readb(&PacketP->control));
+				rio_dprintk(RIO_DEBUG_INTR, " csum	   = %d\n", readw(&PacketP->csum));
+				rio_dprintk(RIO_DEBUG_INTR, "	 data bytes: ");
+				for (DataCnt = 0; DataCnt < PKT_MAX_DATA_LEN; DataCnt++)
+					rio_dprintk(RIO_DEBUG_INTR, "%d\n", readb(&PacketP->data[DataCnt]));
+				remove_receive(PortP);
+				put_free_end(PortP->HostP, PacketP);
+				continue;	/* with next packet */
+			}
+
+			/*
+			 ** How many characters can we move 'upstream' ?
+			 **
+			 ** Determine the minimum of the amount of data
+			 ** available and the amount of space in which to
+			 ** put it.
+			 **
+			 ** 1.        Get the packet length by masking 'len'
+			 **   for only the length bits.
+			 ** 2.        Available space is [buffer size] - [space used]
+			 **
+			 ** Transfer count is the minimum of packet length
+			 ** and available space.
+			 */
+
+			transCount = tty_buffer_request_room(TtyP, readb(&PacketP->len) & PKT_LEN_MASK);
+			rio_dprintk(RIO_DEBUG_REC, "port %d: Copy %d bytes\n", PortP->PortNum, transCount);
+			/*
+			 ** To use the following 'kkprintfs' for debugging - change the '#undef'
+			 ** to '#define', (this is the only place ___DEBUG_IT___ occurs in the
+			 ** driver).
+			 */
+			ptr = (unsigned char __iomem *) PacketP->data + PortP->RxDataStart;
+
+			tty_prepare_flip_string(TtyP, &buf, transCount);
+			rio_memcpy_fromio(buf, ptr, transCount);
+			PortP->RxDataStart += transCount;
+			writeb(readb(&PacketP->len)-transCount, &PacketP->len);
+			copied += transCount;
+
+
+
+			if (readb(&PacketP->len) == 0) {
+				/*
+				 ** If we have emptied the packet, then we can
+				 ** free it, and reset the start pointer for
+				 ** the next packet.
+				 */
+				remove_receive(PortP);
+				put_free_end(PortP->HostP, PacketP);
+				PortP->RxDataStart = 0;
+			}
+		}
+	}
+	if (copied) {
+		rio_dprintk(RIO_DEBUG_REC, "port %d: pushing tty flip buffer: %d total bytes copied.\n", PortP->PortNum, copied);
+		tty_flip_buffer_push(TtyP);
+	}
+
+	return;
+}
+
diff --git a/drivers/staging/generic_serial/rio/rioioctl.h b/drivers/staging/generic_serial/rio/rioioctl.h
new file mode 100644
index 0000000..e8af5b3
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioioctl.h
@@ -0,0 +1,57 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioioctl.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)rioioctl.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef	__rioioctl_h__
+#define	__rioioctl_h__
+
+/*
+** RIO device driver - user ioctls and associated structures.
+*/
+
+struct portStats {
+	int port;
+	int gather;
+	unsigned long txchars;
+	unsigned long rxchars;
+	unsigned long opens;
+	unsigned long closes;
+	unsigned long ioctls;
+};
+
+#define	RIOC	('R'<<8)|('i'<<16)|('o'<<24)
+
+#define	RIO_QUICK_CHECK	  	(RIOC | 105)
+#define RIO_GATHER_PORT_STATS	(RIOC | 193)
+#define RIO_RESET_PORT_STATS	(RIOC | 194)
+#define RIO_GET_PORT_STATS	(RIOC | 195)
+
+#endif				/* __rioioctl_h__ */
diff --git a/drivers/staging/generic_serial/rio/rioparam.c b/drivers/staging/generic_serial/rio/rioparam.c
new file mode 100644
index 0000000..6415f3f
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioparam.c
@@ -0,0 +1,663 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioparam.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:45
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioparam.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+
+
+/*
+** The Scam, based on email from jeremyr@bugs.specialix.co.uk....
+**
+** To send a command on a particular port, you put a packet with the
+** command bit set onto the port. The command bit is in the len field,
+** and gets ORed in with the actual byte count.
+**
+** When you send a packet with the command bit set the first
+** data byte (data[0]) is interpreted as the command to execute.
+** It also governs what data structure overlay should accompany the packet.
+** Commands are defined in cirrus/cirrus.h
+**
+** If you want the command to pre-emt data already on the queue for the
+** port, set the pre-emptive bit in conjunction with the command bit.
+** It is not defined what will happen if you set the preemptive bit
+** on a packet that is NOT a command.
+**
+** Pre-emptive commands should be queued at the head of the queue using
+** add_start(), whereas normal commands and data are enqueued using
+** add_end().
+**
+** Most commands do not use the remaining bytes in the data array. The
+** exceptions are OPEN MOPEN and CONFIG. (NB. As with the SI CONFIG and
+** OPEN are currently analogous). With these three commands the following
+** 11 data bytes are all used to pass config information such as baud rate etc.
+** The fields are also defined in cirrus.h. Some contain straightforward
+** information such as the transmit XON character. Two contain the transmit and
+** receive baud rates respectively. For most baud rates there is a direct
+** mapping between the rates defined in <sys/termio.h> and the byte in the
+** packet. There are additional (non UNIX-standard) rates defined in
+** /u/dos/rio/cirrus/h/brates.h.
+**
+** The rest of the data fields contain approximations to the Cirrus registers
+** that are used to program number of bits etc. Each registers bit fields is
+** defined in cirrus.h.
+** 
+** NB. Only use those bits that are defined as being driver specific
+** or common to the RTA and the driver.
+** 
+** All commands going from RTA->Host will be dealt with by the Host code - you
+** will never see them. As with the SI there will be three fields to look out
+** for in each phb (not yet defined - needs defining a.s.a.p).
+** 
+** modem_status	- current state of handshake pins.
+**
+** port_status	 - current port status - equivalent to hi_stat for SI, indicates
+** if port is IDLE_OPEN, IDLE_CLOSED etc.
+**
+** break_status	- bit X set if break has been received.
+** 
+** Happy hacking.
+** 
+*/
+
+/* 
+** RIOParam is used to open or configure a port. You pass it a PortP,
+** which will have a tty struct attached to it. You also pass a command,
+** either OPEN or CONFIG. The port's setup is taken from the t_ fields
+** of the tty struct inside the PortP, and the port is either opened
+** or re-configured. You must also tell RIOParam if the device is a modem
+** device or not (i.e. top bit of minor number set or clear - take special
+** care when deciding on this!).
+** RIOParam neither flushes nor waits for drain, and is NOT preemptive.
+**
+** RIOParam assumes it will be called at splrio(), and also assumes
+** that CookMode is set correctly in the port structure.
+**
+** NB. for MPX
+**	tty lock must NOT have been previously acquired.
+*/
+int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
+{
+	struct tty_struct *TtyP;
+	int retval;
+	struct phb_param __iomem *phb_param_ptr;
+	struct PKT __iomem *PacketP;
+	int res;
+	u8 Cor1 = 0, Cor2 = 0, Cor4 = 0, Cor5 = 0;
+	u8 TxXon = 0, TxXoff = 0, RxXon = 0, RxXoff = 0;
+	u8 LNext = 0, TxBaud = 0, RxBaud = 0;
+	int retries = 0xff;
+	unsigned long flags;
+
+	func_enter();
+
+	TtyP = PortP->gs.port.tty;
+
+	rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP);
+
+	if (!TtyP) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n");
+
+		func_exit();
+
+		return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	if (cmd == RIOC_OPEN) {
+		/*
+		 ** If the port is set to store or lock the parameters, and it is
+		 ** paramed with OPEN, we want to restore the saved port termio, but
+		 ** only if StoredTermio has been saved, i.e. NOT 1st open after reboot.
+		 */
+	}
+
+	/*
+	 ** wait for space
+	 */
+	while (!(res = can_add_transmit(&PacketP, PortP)) || (PortP->InUse != NOT_INUSE)) {
+		if (retries-- <= 0) {
+			break;
+		}
+		if (PortP->InUse != NOT_INUSE) {
+			rio_dprintk(RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n");
+		}
+
+		if (!res) {
+			rio_dprintk(RIO_DEBUG_PARAM, "Port has no space on transmit queue\n");
+		}
+
+		if (SleepFlag != OK_TO_SLEEP) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			func_exit();
+
+			return RIO_FAIL;
+		}
+
+		rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit\n");
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		retval = RIODelay(PortP, HUNDRED_MS);
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		if (retval == RIO_FAIL) {
+			rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n");
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			func_exit();
+			return -EINTR;
+		}
+		if (PortP->State & RIO_DELETED) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			func_exit();
+			return 0;
+		}
+	}
+
+	if (!res) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		func_exit();
+
+		return RIO_FAIL;
+	}
+
+	rio_dprintk(RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n", res);
+	rio_dprintk(RIO_DEBUG_PARAM, "Packet is %p\n", PacketP);
+
+	phb_param_ptr = (struct phb_param __iomem *) PacketP->data;
+
+
+	switch (TtyP->termios->c_cflag & CSIZE) {
+	case CS5:
+		{
+			rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
+			Cor1 |= RIOC_COR1_5BITS;
+			break;
+		}
+	case CS6:
+		{
+			rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
+			Cor1 |= RIOC_COR1_6BITS;
+			break;
+		}
+	case CS7:
+		{
+			rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
+			Cor1 |= RIOC_COR1_7BITS;
+			break;
+		}
+	case CS8:
+		{
+			rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
+			Cor1 |= RIOC_COR1_8BITS;
+			break;
+		}
+	}
+
+	if (TtyP->termios->c_cflag & CSTOPB) {
+		rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
+		Cor1 |= RIOC_COR1_2STOP;
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
+		Cor1 |= RIOC_COR1_1STOP;
+	}
+
+	if (TtyP->termios->c_cflag & PARENB) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
+		Cor1 |= RIOC_COR1_NORMAL;
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
+		Cor1 |= RIOC_COR1_NOP;
+	}
+	if (TtyP->termios->c_cflag & PARODD) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
+		Cor1 |= RIOC_COR1_ODD;
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
+		Cor1 |= RIOC_COR1_EVEN;
+	}
+
+	/*
+	 ** COR 2
+	 */
+	if (TtyP->termios->c_iflag & IXON) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
+		Cor2 |= RIOC_COR2_IXON;
+	} else {
+		if (PortP->Config & RIO_IXON) {
+			rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
+			Cor2 |= RIOC_COR2_IXON;
+		} else
+			rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
+	}
+
+	if (TtyP->termios->c_iflag & IXANY) {
+		if (PortP->Config & RIO_IXANY) {
+			rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
+			Cor2 |= RIOC_COR2_IXANY;
+		} else
+			rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
+	}
+
+	if (TtyP->termios->c_iflag & IXOFF) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
+		Cor2 |= RIOC_COR2_IXOFF;
+	}
+
+	if (TtyP->termios->c_cflag & HUPCL) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
+		Cor2 |= RIOC_COR2_HUPCL;
+	}
+
+	if (C_CRTSCTS(TtyP)) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
+		Cor2 |= RIOC_COR2_CTSFLOW;
+		Cor2 |= RIOC_COR2_RTSFLOW;
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
+		Cor2 &= ~RIOC_COR2_CTSFLOW;
+		Cor2 &= ~RIOC_COR2_RTSFLOW;
+	}
+
+
+	if (TtyP->termios->c_cflag & CLOCAL) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Local line\n");
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "Possible Modem line\n");
+	}
+
+	/*
+	 ** COR 4 (there is no COR 3)
+	 */
+	if (TtyP->termios->c_iflag & IGNBRK) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
+		Cor4 |= RIOC_COR4_IGNBRK;
+	}
+	if (!(TtyP->termios->c_iflag & BRKINT)) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
+		Cor4 |= RIOC_COR4_NBRKINT;
+	} else {
+		rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on	break condition\n");
+	}
+
+	if (TtyP->termios->c_iflag & INLCR) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
+		Cor4 |= RIOC_COR4_INLCR;
+	}
+
+	if (TtyP->termios->c_iflag & IGNCR) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
+		Cor4 |= RIOC_COR4_IGNCR;
+	}
+
+	if (TtyP->termios->c_iflag & ICRNL) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
+		Cor4 |= RIOC_COR4_ICRNL;
+	}
+	if (TtyP->termios->c_iflag & IGNPAR) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
+		Cor4 |= RIOC_COR4_IGNPAR;
+	}
+	if (TtyP->termios->c_iflag & PARMRK) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
+		Cor4 |= RIOC_COR4_PARMRK;
+	}
+
+	/*
+	 ** Set the RAISEMOD flag to ensure that the modem lines are raised
+	 ** on reception of a config packet.
+	 ** The download code handles the zero baud condition.
+	 */
+	Cor4 |= RIOC_COR4_RAISEMOD;
+
+	/*
+	 ** COR 5
+	 */
+
+	Cor5 = RIOC_COR5_CMOE;
+
+	/*
+	 ** Set to monitor tbusy/tstop (or not).
+	 */
+
+	if (PortP->MonitorTstate)
+		Cor5 |= RIOC_COR5_TSTATE_ON;
+	else
+		Cor5 |= RIOC_COR5_TSTATE_OFF;
+
+	/*
+	 ** Could set LNE here if you wanted LNext processing. SVR4 will use it.
+	 */
+	if (TtyP->termios->c_iflag & ISTRIP) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
+		if (!(PortP->State & RIO_TRIAD_MODE)) {
+			Cor5 |= RIOC_COR5_ISTRIP;
+		}
+	}
+
+	if (TtyP->termios->c_oflag & ONLCR) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
+		if (PortP->CookMode == COOK_MEDIUM)
+			Cor5 |= RIOC_COR5_ONLCR;
+	}
+	if (TtyP->termios->c_oflag & OCRNL) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
+		if (PortP->CookMode == COOK_MEDIUM)
+			Cor5 |= RIOC_COR5_OCRNL;
+	}
+	if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
+		rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
+		if (PortP->CookMode == COOK_MEDIUM)
+			Cor5 |= RIOC_COR5_TAB3;
+	}
+
+	/*
+	 ** Flow control bytes.
+	 */
+	TxXon = TtyP->termios->c_cc[VSTART];
+	TxXoff = TtyP->termios->c_cc[VSTOP];
+	RxXon = TtyP->termios->c_cc[VSTART];
+	RxXoff = TtyP->termios->c_cc[VSTOP];
+	/*
+	 ** LNEXT byte
+	 */
+	LNext = 0;
+
+	/*
+	 ** Baud rate bytes
+	 */
+	rio_dprintk(RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", TtyP->termios->c_cflag, CBAUD);
+
+	switch (TtyP->termios->c_cflag & CBAUD) {
+#define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break
+		e(50);
+		e(75);
+		e(110);
+		e(134);
+		e(150);
+		e(200);
+		e(300);
+		e(600);
+		e(1200);
+		e(1800);
+		e(2400);
+		e(4800);
+		e(9600);
+		e(19200);
+		e(38400);
+		e(57600);
+		e(115200);	/* e(230400);e(460800); e(921600);  */
+	}
+
+	rio_dprintk(RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud);
+
+
+	/*
+	 ** Leftovers
+	 */
+	if (TtyP->termios->c_cflag & CREAD)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable receiver\n");
+#ifdef RCV1EN
+	if (TtyP->termios->c_cflag & RCV1EN)
+		rio_dprintk(RIO_DEBUG_PARAM, "RCV1EN (?)\n");
+#endif
+#ifdef XMT1EN
+	if (TtyP->termios->c_cflag & XMT1EN)
+		rio_dprintk(RIO_DEBUG_PARAM, "XMT1EN (?)\n");
+#endif
+	if (TtyP->termios->c_lflag & ISIG)
+		rio_dprintk(RIO_DEBUG_PARAM, "Input character signal generating enabled\n");
+	if (TtyP->termios->c_lflag & ICANON)
+		rio_dprintk(RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n");
+	if (TtyP->termios->c_lflag & XCASE)
+		rio_dprintk(RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n");
+	if (TtyP->termios->c_lflag & ECHO)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable input echo\n");
+	if (TtyP->termios->c_lflag & ECHOE)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable echo erase\n");
+	if (TtyP->termios->c_lflag & ECHOK)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable echo kill\n");
+	if (TtyP->termios->c_lflag & ECHONL)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable echo newline\n");
+	if (TtyP->termios->c_lflag & NOFLSH)
+		rio_dprintk(RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n");
+#ifdef TOSTOP
+	if (TtyP->termios->c_lflag & TOSTOP)
+		rio_dprintk(RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n");
+#endif
+#ifdef XCLUDE
+	if (TtyP->termios->c_lflag & XCLUDE)
+		rio_dprintk(RIO_DEBUG_PARAM, "Exclusive use of this line\n");
+#endif
+	if (TtyP->termios->c_iflag & IUCLC)
+		rio_dprintk(RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n");
+	if (TtyP->termios->c_oflag & OPOST)
+		rio_dprintk(RIO_DEBUG_PARAM, "Enable output post-processing\n");
+	if (TtyP->termios->c_oflag & OLCUC)
+		rio_dprintk(RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n");
+	if (TtyP->termios->c_oflag & ONOCR)
+		rio_dprintk(RIO_DEBUG_PARAM, "No carriage return output at column 0\n");
+	if (TtyP->termios->c_oflag & ONLRET)
+		rio_dprintk(RIO_DEBUG_PARAM, "Newline performs carriage return function\n");
+	if (TtyP->termios->c_oflag & OFILL)
+		rio_dprintk(RIO_DEBUG_PARAM, "Use fill characters for delay\n");
+	if (TtyP->termios->c_oflag & OFDEL)
+		rio_dprintk(RIO_DEBUG_PARAM, "Fill character is DEL\n");
+	if (TtyP->termios->c_oflag & NLDLY)
+		rio_dprintk(RIO_DEBUG_PARAM, "Newline delay set\n");
+	if (TtyP->termios->c_oflag & CRDLY)
+		rio_dprintk(RIO_DEBUG_PARAM, "Carriage return delay set\n");
+	if (TtyP->termios->c_oflag & TABDLY)
+		rio_dprintk(RIO_DEBUG_PARAM, "Tab delay set\n");
+	/*
+	 ** These things are kind of useful in a later life!
+	 */
+	PortP->Cor2Copy = Cor2;
+
+	if (PortP->State & RIO_DELETED) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		func_exit();
+
+		return RIO_FAIL;
+	}
+
+	/*
+	 ** Actually write the info into the packet to be sent
+	 */
+	writeb(cmd, &phb_param_ptr->Cmd);
+	writeb(Cor1, &phb_param_ptr->Cor1);
+	writeb(Cor2, &phb_param_ptr->Cor2);
+	writeb(Cor4, &phb_param_ptr->Cor4);
+	writeb(Cor5, &phb_param_ptr->Cor5);
+	writeb(TxXon, &phb_param_ptr->TxXon);
+	writeb(RxXon, &phb_param_ptr->RxXon);
+	writeb(TxXoff, &phb_param_ptr->TxXoff);
+	writeb(RxXoff, &phb_param_ptr->RxXoff);
+	writeb(LNext, &phb_param_ptr->LNext);
+	writeb(TxBaud, &phb_param_ptr->TxBaud);
+	writeb(RxBaud, &phb_param_ptr->RxBaud);
+
+	/*
+	 ** Set the length/command field
+	 */
+	writeb(12 | PKT_CMD_BIT, &PacketP->len);
+
+	/*
+	 ** The packet is formed - now, whack it off
+	 ** to its final destination:
+	 */
+	add_transmit(PortP);
+	/*
+	 ** Count characters transmitted for port statistics reporting
+	 */
+	if (PortP->statsGather)
+		PortP->txchars += 12;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	rio_dprintk(RIO_DEBUG_PARAM, "add_transmit returned.\n");
+	/*
+	 ** job done.
+	 */
+	func_exit();
+
+	return 0;
+}
+
+
+/*
+** We can add another packet to a transmit queue if the packet pointer pointed
+** to by the TxAdd pointer has PKT_IN_USE clear in its address.
+*/
+int can_add_transmit(struct PKT __iomem **PktP, struct Port *PortP)
+{
+	struct PKT __iomem *tp;
+
+	*PktP = tp = (struct PKT __iomem *) RIO_PTR(PortP->Caddr, readw(PortP->TxAdd));
+
+	return !((unsigned long) tp & PKT_IN_USE);
+}
+
+/*
+** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
+** and then move the TxAdd pointer along one position to point to the next
+** packet pointer. You must wrap the pointer from the end back to the start.
+*/
+void add_transmit(struct Port *PortP)
+{
+	if (readw(PortP->TxAdd) & PKT_IN_USE) {
+		rio_dprintk(RIO_DEBUG_PARAM, "add_transmit: Packet has been stolen!");
+	}
+	writew(readw(PortP->TxAdd) | PKT_IN_USE, PortP->TxAdd);
+	PortP->TxAdd = (PortP->TxAdd == PortP->TxEnd) ? PortP->TxStart : PortP->TxAdd + 1;
+	writew(RIO_OFF(PortP->Caddr, PortP->TxAdd), &PortP->PhbP->tx_add);
+}
+
+/****************************************
+ * Put a packet onto the end of the
+ * free list
+ ****************************************/
+void put_free_end(struct Host *HostP, struct PKT __iomem *PktP)
+{
+	struct rio_free_list __iomem *tmp_pointer;
+	unsigned short old_end, new_end;
+	unsigned long flags;
+
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+	 /*************************************************
+	* Put a packet back onto the back of the free list
+	*
+	************************************************/
+
+	rio_dprintk(RIO_DEBUG_PFE, "put_free_end(PktP=%p)\n", PktP);
+
+	if ((old_end = readw(&HostP->ParmMapP->free_list_end)) != TPNULL) {
+		new_end = RIO_OFF(HostP->Caddr, PktP);
+		tmp_pointer = (struct rio_free_list __iomem *) RIO_PTR(HostP->Caddr, old_end);
+		writew(new_end, &tmp_pointer->next);
+		writew(old_end, &((struct rio_free_list __iomem *) PktP)->prev);
+		writew(TPNULL, &((struct rio_free_list __iomem *) PktP)->next);
+		writew(new_end, &HostP->ParmMapP->free_list_end);
+	} else {		/* First packet on the free list this should never happen! */
+		rio_dprintk(RIO_DEBUG_PFE, "put_free_end(): This should never happen\n");
+		writew(RIO_OFF(HostP->Caddr, PktP), &HostP->ParmMapP->free_list_end);
+		tmp_pointer = (struct rio_free_list __iomem *) PktP;
+		writew(TPNULL, &tmp_pointer->prev);
+		writew(TPNULL, &tmp_pointer->next);
+	}
+	rio_dprintk(RIO_DEBUG_CMD, "Before unlock: %p\n", &HostP->HostLock);
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+}
+
+/*
+** can_remove_receive(PktP,P) returns non-zero if PKT_IN_USE is set
+** for the next packet on the queue. It will also set PktP to point to the
+** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
+** then can_remove_receive() returns 0.
+*/
+int can_remove_receive(struct PKT __iomem **PktP, struct Port *PortP)
+{
+	if (readw(PortP->RxRemove) & PKT_IN_USE) {
+		*PktP = (struct PKT __iomem *) RIO_PTR(PortP->Caddr, readw(PortP->RxRemove) & ~PKT_IN_USE);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+** To remove a packet from the receive queue you clear its PKT_IN_USE bit,
+** and then bump the pointers. Once the pointers get to the end, they must
+** be wrapped back to the start.
+*/
+void remove_receive(struct Port *PortP)
+{
+	writew(readw(PortP->RxRemove) & ~PKT_IN_USE, PortP->RxRemove);
+	PortP->RxRemove = (PortP->RxRemove == PortP->RxEnd) ? PortP->RxStart : PortP->RxRemove + 1;
+	writew(RIO_OFF(PortP->Caddr, PortP->RxRemove), &PortP->PhbP->rx_remove);
+}
diff --git a/drivers/staging/generic_serial/rio/rioroute.c b/drivers/staging/generic_serial/rio/rioroute.c
new file mode 100644
index 0000000..f9b936a
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rioroute.c
@@ -0,0 +1,1039 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: rioroute.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:46
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)rioroute.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+static int RIOCheckIsolated(struct rio_info *, struct Host *, unsigned int);
+static int RIOIsolate(struct rio_info *, struct Host *, unsigned int);
+static int RIOCheck(struct Host *, unsigned int);
+static void RIOConCon(struct rio_info *, struct Host *, unsigned int, unsigned int, unsigned int, unsigned int, int);
+
+
+/*
+** Incoming on the ROUTE_RUP
+** I wrote this while I was tired. Forgive me.
+*/
+int RIORouteRup(struct rio_info *p, unsigned int Rup, struct Host *HostP, struct PKT __iomem * PacketP)
+{
+	struct PktCmd __iomem *PktCmdP = (struct PktCmd __iomem *) PacketP->data;
+	struct PktCmd_M *PktReplyP;
+	struct CmdBlk *CmdBlkP;
+	struct Port *PortP;
+	struct Map *MapP;
+	struct Top *TopP;
+	int ThisLink, ThisLinkMin, ThisLinkMax;
+	int port;
+	int Mod, Mod1, Mod2;
+	unsigned short RtaType;
+	unsigned int RtaUniq;
+	unsigned int ThisUnit, ThisUnit2;	/* 2 ids to accommodate 16 port RTA */
+	unsigned int OldUnit, NewUnit, OldLink, NewLink;
+	char *MyType, *MyName;
+	int Lies;
+	unsigned long flags;
+
+	/*
+	 ** Is this unit telling us it's current link topology?
+	 */
+	if (readb(&PktCmdP->Command) == ROUTE_TOPOLOGY) {
+		MapP = HostP->Mapping;
+
+		/*
+		 ** The packet can be sent either by the host or by an RTA.
+		 ** If it comes from the host, then we need to fill in the
+		 ** Topology array in the host structure. If it came in
+		 ** from an RTA then we need to fill in the Mapping structure's
+		 ** Topology array for the unit.
+		 */
+		if (Rup >= (unsigned short) MAX_RUP) {
+			ThisUnit = HOST_ID;
+			TopP = HostP->Topology;
+			MyType = "Host";
+			MyName = HostP->Name;
+			ThisLinkMin = ThisLinkMax = Rup - MAX_RUP;
+		} else {
+			ThisUnit = Rup + 1;
+			TopP = HostP->Mapping[Rup].Topology;
+			MyType = "RTA";
+			MyName = HostP->Mapping[Rup].Name;
+			ThisLinkMin = 0;
+			ThisLinkMax = LINKS_PER_UNIT - 1;
+		}
+
+		/*
+		 ** Lies will not be tolerated.
+		 ** If any pair of links claim to be connected to the same
+		 ** place, then ignore this packet completely.
+		 */
+		Lies = 0;
+		for (ThisLink = ThisLinkMin + 1; ThisLink <= ThisLinkMax; ThisLink++) {
+			/*
+			 ** it won't lie about network interconnect, total disconnects
+			 ** and no-IDs. (or at least, it doesn't *matter* if it does)
+			 */
+			if (readb(&PktCmdP->RouteTopology[ThisLink].Unit) > (unsigned short) MAX_RUP)
+				continue;
+
+			for (NewLink = ThisLinkMin; NewLink < ThisLink; NewLink++) {
+				if ((readb(&PktCmdP->RouteTopology[ThisLink].Unit) == readb(&PktCmdP->RouteTopology[NewLink].Unit)) && (readb(&PktCmdP->RouteTopology[ThisLink].Link) == readb(&PktCmdP->RouteTopology[NewLink].Link))) {
+					Lies++;
+				}
+			}
+		}
+
+		if (Lies) {
+			rio_dprintk(RIO_DEBUG_ROUTE, "LIES! DAMN LIES! %d LIES!\n", Lies);
+			rio_dprintk(RIO_DEBUG_ROUTE, "%d:%c %d:%c %d:%c %d:%c\n",
+				    readb(&PktCmdP->RouteTopology[0].Unit),
+				    'A' + readb(&PktCmdP->RouteTopology[0].Link),
+				    readb(&PktCmdP->RouteTopology[1].Unit),
+				    'A' + readb(&PktCmdP->RouteTopology[1].Link), readb(&PktCmdP->RouteTopology[2].Unit), 'A' + readb(&PktCmdP->RouteTopology[2].Link), readb(&PktCmdP->RouteTopology[3].Unit), 'A' + readb(&PktCmdP->RouteTopology[3].Link));
+			return 1;
+		}
+
+		/*
+		 ** now, process each link.
+		 */
+		for (ThisLink = ThisLinkMin; ThisLink <= ThisLinkMax; ThisLink++) {
+			/*
+			 ** this is what it was connected to
+			 */
+			OldUnit = TopP[ThisLink].Unit;
+			OldLink = TopP[ThisLink].Link;
+
+			/*
+			 ** this is what it is now connected to
+			 */
+			NewUnit = readb(&PktCmdP->RouteTopology[ThisLink].Unit);
+			NewLink = readb(&PktCmdP->RouteTopology[ThisLink].Link);
+
+			if (OldUnit != NewUnit || OldLink != NewLink) {
+				/*
+				 ** something has changed!
+				 */
+
+				if (NewUnit > MAX_RUP && NewUnit != ROUTE_DISCONNECT && NewUnit != ROUTE_NO_ID && NewUnit != ROUTE_INTERCONNECT) {
+					rio_dprintk(RIO_DEBUG_ROUTE, "I have a link from %s %s to unit %d:%d - I don't like it.\n", MyType, MyName, NewUnit, NewLink);
+				} else {
+					/*
+					 ** put the new values in
+					 */
+					TopP[ThisLink].Unit = NewUnit;
+					TopP[ThisLink].Link = NewLink;
+
+					RIOSetChange(p);
+
+					if (OldUnit <= MAX_RUP) {
+						/*
+						 ** If something has become bust, then re-enable them messages
+						 */
+						if (!p->RIONoMessage)
+							RIOConCon(p, HostP, ThisUnit, ThisLink, OldUnit, OldLink, DISCONNECT);
+					}
+
+					if ((NewUnit <= MAX_RUP) && !p->RIONoMessage)
+						RIOConCon(p, HostP, ThisUnit, ThisLink, NewUnit, NewLink, CONNECT);
+
+					if (NewUnit == ROUTE_NO_ID)
+						rio_dprintk(RIO_DEBUG_ROUTE, "%s %s (%c) is connected to an unconfigured unit.\n", MyType, MyName, 'A' + ThisLink);
+
+					if (NewUnit == ROUTE_INTERCONNECT) {
+						if (!p->RIONoMessage)
+							printk(KERN_DEBUG "rio: %s '%s' (%c) is connected to another network.\n", MyType, MyName, 'A' + ThisLink);
+					}
+
+					/*
+					 ** perform an update for 'the other end', so that these messages
+					 ** only appears once. Only disconnect the other end if it is pointing
+					 ** at us!
+					 */
+					if (OldUnit == HOST_ID) {
+						if (HostP->Topology[OldLink].Unit == ThisUnit && HostP->Topology[OldLink].Link == ThisLink) {
+							rio_dprintk(RIO_DEBUG_ROUTE, "SETTING HOST (%c) TO DISCONNECTED!\n", OldLink + 'A');
+							HostP->Topology[OldLink].Unit = ROUTE_DISCONNECT;
+							HostP->Topology[OldLink].Link = NO_LINK;
+						} else {
+							rio_dprintk(RIO_DEBUG_ROUTE, "HOST(%c) WAS NOT CONNECTED TO %s (%c)!\n", OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A');
+						}
+					} else if (OldUnit <= MAX_RUP) {
+						if (HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit == ThisUnit && HostP->Mapping[OldUnit - 1].Topology[OldLink].Link == ThisLink) {
+							rio_dprintk(RIO_DEBUG_ROUTE, "SETTING RTA %s (%c) TO DISCONNECTED!\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A');
+							HostP->Mapping[OldUnit - 1].Topology[OldLink].Unit = ROUTE_DISCONNECT;
+							HostP->Mapping[OldUnit - 1].Topology[OldLink].Link = NO_LINK;
+						} else {
+							rio_dprintk(RIO_DEBUG_ROUTE, "RTA %s (%c) WAS NOT CONNECTED TO %s (%c)\n", HostP->Mapping[OldUnit - 1].Name, OldLink + 'A', HostP->Mapping[ThisUnit - 1].Name, ThisLink + 'A');
+						}
+					}
+					if (NewUnit == HOST_ID) {
+						rio_dprintk(RIO_DEBUG_ROUTE, "MARKING HOST (%c) CONNECTED TO %s (%c)\n", NewLink + 'A', MyName, ThisLink + 'A');
+						HostP->Topology[NewLink].Unit = ThisUnit;
+						HostP->Topology[NewLink].Link = ThisLink;
+					} else if (NewUnit <= MAX_RUP) {
+						rio_dprintk(RIO_DEBUG_ROUTE, "MARKING RTA %s (%c) CONNECTED TO %s (%c)\n", HostP->Mapping[NewUnit - 1].Name, NewLink + 'A', MyName, ThisLink + 'A');
+						HostP->Mapping[NewUnit - 1].Topology[NewLink].Unit = ThisUnit;
+						HostP->Mapping[NewUnit - 1].Topology[NewLink].Link = ThisLink;
+					}
+				}
+				RIOSetChange(p);
+				RIOCheckIsolated(p, HostP, OldUnit);
+			}
+		}
+		return 1;
+	}
+
+	/*
+	 ** The only other command we recognise is a route_request command
+	 */
+	if (readb(&PktCmdP->Command) != ROUTE_REQUEST) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unknown command %d received on rup %d host %p ROUTE_RUP\n", readb(&PktCmdP->Command), Rup, HostP);
+		return 1;
+	}
+
+	RtaUniq = (readb(&PktCmdP->UniqNum[0])) + (readb(&PktCmdP->UniqNum[1]) << 8) + (readb(&PktCmdP->UniqNum[2]) << 16) + (readb(&PktCmdP->UniqNum[3]) << 24);
+
+	/*
+	 ** Determine if 8 or 16 port RTA
+	 */
+	RtaType = GetUnitType(RtaUniq);
+
+	rio_dprintk(RIO_DEBUG_ROUTE, "Received a request for an ID for serial number %x\n", RtaUniq);
+
+	Mod = readb(&PktCmdP->ModuleTypes);
+	Mod1 = LONYBLE(Mod);
+	if (RtaType == TYPE_RTA16) {
+		/*
+		 ** Only one ident is set for a 16 port RTA. To make compatible
+		 ** with 8 port, set 2nd ident in Mod2 to the same as Mod1.
+		 */
+		Mod2 = Mod1;
+		rio_dprintk(RIO_DEBUG_ROUTE, "Backplane type is %s (all ports)\n", p->RIOModuleTypes[Mod1].Name);
+	} else {
+		Mod2 = HINYBLE(Mod);
+		rio_dprintk(RIO_DEBUG_ROUTE, "Module types are %s (ports 0-3) and %s (ports 4-7)\n", p->RIOModuleTypes[Mod1].Name, p->RIOModuleTypes[Mod2].Name);
+	}
+
+	/*
+	 ** try to unhook a command block from the command free list.
+	 */
+	if (!(CmdBlkP = RIOGetCmdBlk())) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "No command blocks to route RTA! come back later.\n");
+		return 0;
+	}
+
+	/*
+	 ** Fill in the default info on the command block
+	 */
+	CmdBlkP->Packet.dest_unit = Rup;
+	CmdBlkP->Packet.dest_port = ROUTE_RUP;
+	CmdBlkP->Packet.src_unit = HOST_ID;
+	CmdBlkP->Packet.src_port = ROUTE_RUP;
+	CmdBlkP->Packet.len = PKT_CMD_BIT | 1;
+	CmdBlkP->PreFuncP = CmdBlkP->PostFuncP = NULL;
+	PktReplyP = (struct PktCmd_M *) CmdBlkP->Packet.data;
+
+	if (!RIOBootOk(p, HostP, RtaUniq)) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "RTA %x tried to get an ID, but does not belong - FOAD it!\n", RtaUniq);
+		PktReplyP->Command = ROUTE_FOAD;
+		memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+		RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+		return 1;
+	}
+
+	/*
+	 ** Check to see if the RTA is configured for this host
+	 */
+	for (ThisUnit = 0; ThisUnit < MAX_RUP; ThisUnit++) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Entry %d Flags=%s %s UniqueNum=0x%x\n",
+			    ThisUnit, HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE ? "Slot-In-Use" : "Not In Use", HostP->Mapping[ThisUnit].Flags & SLOT_TENTATIVE ? "Slot-Tentative" : "Not Tentative", HostP->Mapping[ThisUnit].RtaUniqueNum);
+
+		/*
+		 ** We have an entry for it.
+		 */
+		if ((HostP->Mapping[ThisUnit].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) && (HostP->Mapping[ThisUnit].RtaUniqueNum == RtaUniq)) {
+			if (RtaType == TYPE_RTA16) {
+				ThisUnit2 = HostP->Mapping[ThisUnit].ID2 - 1;
+				rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slots %d+%d\n", RtaUniq, ThisUnit, ThisUnit2);
+			} else
+				rio_dprintk(RIO_DEBUG_ROUTE, "Found unit 0x%x at slot %d\n", RtaUniq, ThisUnit);
+			/*
+			 ** If we have no knowledge of booting it, then the host has
+			 ** been re-booted, and so we must kill the RTA, so that it
+			 ** will be booted again (potentially with new bins)
+			 ** and it will then re-ask for an ID, which we will service.
+			 */
+			if ((HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE) && !(HostP->Mapping[ThisUnit].Flags & RTA_BOOTED)) {
+				if (!(HostP->Mapping[ThisUnit].Flags & MSG_DONE)) {
+					if (!p->RIONoMessage)
+						printk(KERN_DEBUG "rio: RTA '%s' is being updated.\n", HostP->Mapping[ThisUnit].Name);
+					HostP->Mapping[ThisUnit].Flags |= MSG_DONE;
+				}
+				PktReplyP->Command = ROUTE_FOAD;
+				memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+				RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+				return 1;
+			}
+
+			/*
+			 ** Send the ID (entry) to this RTA. The ID number is implicit as
+			 ** the offset into the table. It is worth noting at this stage
+			 ** that offset zero in the table contains the entries for the
+			 ** RTA with ID 1!!!!
+			 */
+			PktReplyP->Command = ROUTE_ALLOCATE;
+			PktReplyP->IDNum = ThisUnit + 1;
+			if (RtaType == TYPE_RTA16) {
+				if (HostP->Mapping[ThisUnit].Flags & SLOT_IN_USE)
+					/*
+					 ** Adjust the phb and tx pkt dest_units for 2nd block of 8
+					 ** only if the RTA has ports associated (SLOT_IN_USE)
+					 */
+					RIOFixPhbs(p, HostP, ThisUnit2);
+				PktReplyP->IDNum2 = ThisUnit2 + 1;
+				rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated IDs %d+%d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum, PktReplyP->IDNum2);
+			} else {
+				PktReplyP->IDNum2 = ROUTE_NO_ID;
+				rio_dprintk(RIO_DEBUG_ROUTE, "RTA '%s' has been allocated ID %d\n", HostP->Mapping[ThisUnit].Name, PktReplyP->IDNum);
+			}
+			memcpy(PktReplyP->CommandText, "RT_ALLOCAT", 10);
+
+			RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+
+			/*
+			 ** If this is a freshly booted RTA, then we need to re-open
+			 ** the ports, if any where open, so that data may once more
+			 ** flow around the system!
+			 */
+			if ((HostP->Mapping[ThisUnit].Flags & RTA_NEWBOOT) && (HostP->Mapping[ThisUnit].SysPort != NO_PORT)) {
+				/*
+				 ** look at the ports associated with this beast and
+				 ** see if any where open. If they was, then re-open
+				 ** them, using the info from the tty flags.
+				 */
+				for (port = 0; port < PORTS_PER_RTA; port++) {
+					PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort];
+					if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+						rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
+						rio_spin_lock_irqsave(&PortP->portSem, flags);
+						PortP->MagicFlags |= MAGIC_REBOOT;
+						rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+					}
+				}
+				if (RtaType == TYPE_RTA16) {
+					for (port = 0; port < PORTS_PER_RTA; port++) {
+						PortP = p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort];
+						if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+							rio_dprintk(RIO_DEBUG_ROUTE, "Re-opened this port\n");
+							rio_spin_lock_irqsave(&PortP->portSem, flags);
+							PortP->MagicFlags |= MAGIC_REBOOT;
+							rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+						}
+					}
+				}
+			}
+
+			/*
+			 ** keep a copy of the module types!
+			 */
+			HostP->UnixRups[ThisUnit].ModTypes = Mod;
+			if (RtaType == TYPE_RTA16)
+				HostP->UnixRups[ThisUnit2].ModTypes = Mod;
+
+			/*
+			 ** If either of the modules on this unit is read-only or write-only
+			 ** or none-xprint, then we need to transfer that info over to the
+			 ** relevant ports.
+			 */
+			if (HostP->Mapping[ThisUnit].SysPort != NO_PORT) {
+				for (port = 0; port < PORTS_PER_MODULE; port++) {
+					p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+					p->RIOPortp[port + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+					p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config &= ~RIO_NOMASK;
+					p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+				}
+				if (RtaType == TYPE_RTA16) {
+					for (port = 0; port < PORTS_PER_MODULE; port++) {
+						p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+						p->RIOPortp[port + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod1].Flags[port];
+						p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config &= ~RIO_NOMASK;
+						p->RIOPortp[port + PORTS_PER_MODULE + HostP->Mapping[ThisUnit2].SysPort]->Config |= p->RIOModuleTypes[Mod2].Flags[port];
+					}
+				}
+			}
+
+			/*
+			 ** Job done, get on with the interrupts!
+			 */
+			return 1;
+		}
+	}
+	/*
+	 ** There is no table entry for this RTA at all.
+	 **
+	 ** Lets check to see if we actually booted this unit - if not,
+	 ** then we reset it and it will go round the loop of being booted
+	 ** we can then worry about trying to fit it into the table.
+	 */
+	for (ThisUnit = 0; ThisUnit < HostP->NumExtraBooted; ThisUnit++)
+		if (HostP->ExtraUnits[ThisUnit] == RtaUniq)
+			break;
+	if (ThisUnit == HostP->NumExtraBooted && ThisUnit != MAX_EXTRA_UNITS) {
+		/*
+		 ** if the unit wasn't in the table, and the table wasn't full, then
+		 ** we reset the unit, because we didn't boot it.
+		 ** However, if the table is full, it could be that we did boot
+		 ** this unit, and so we won't reboot it, because it isn't really
+		 ** all that disasterous to keep the old bins in most cases. This
+		 ** is a rather tacky feature, but we are on the edge of reallity
+		 ** here, because the implication is that someone has connected
+		 ** 16+MAX_EXTRA_UNITS onto one host.
+		 */
+		static int UnknownMesgDone = 0;
+
+		if (!UnknownMesgDone) {
+			if (!p->RIONoMessage)
+				printk(KERN_DEBUG "rio: One or more unknown RTAs are being updated.\n");
+			UnknownMesgDone = 1;
+		}
+
+		PktReplyP->Command = ROUTE_FOAD;
+		memcpy(PktReplyP->CommandText, "RT_FOAD", 7);
+	} else {
+		/*
+		 ** we did boot it (as an extra), and there may now be a table
+		 ** slot free (because of a delete), so we will try to make
+		 ** a tentative entry for it, so that the configurator can see it
+		 ** and fill in the details for us.
+		 */
+		if (RtaType == TYPE_RTA16) {
+			if (RIOFindFreeID(p, HostP, &ThisUnit, &ThisUnit2) == 0) {
+				RIODefaultName(p, HostP, ThisUnit);
+				rio_fill_host_slot(ThisUnit, ThisUnit2, RtaUniq, HostP);
+			}
+		} else {
+			if (RIOFindFreeID(p, HostP, &ThisUnit, NULL) == 0) {
+				RIODefaultName(p, HostP, ThisUnit);
+				rio_fill_host_slot(ThisUnit, 0, RtaUniq, HostP);
+			}
+		}
+		PktReplyP->Command = ROUTE_USED;
+		memcpy(PktReplyP->CommandText, "RT_USED", 7);
+	}
+	RIOQueueCmdBlk(HostP, Rup, CmdBlkP);
+	return 1;
+}
+
+
+void RIOFixPhbs(struct rio_info *p, struct Host *HostP, unsigned int unit)
+{
+	unsigned short link, port;
+	struct Port *PortP;
+	unsigned long flags;
+	int PortN = HostP->Mapping[unit].SysPort;
+
+	rio_dprintk(RIO_DEBUG_ROUTE, "RIOFixPhbs unit %d sysport %d\n", unit, PortN);
+
+	if (PortN != -1) {
+		unsigned short dest_unit = HostP->Mapping[unit].ID2;
+
+		/*
+		 ** Get the link number used for the 1st 8 phbs on this unit.
+		 */
+		PortP = p->RIOPortp[HostP->Mapping[dest_unit - 1].SysPort];
+
+		link = readw(&PortP->PhbP->link);
+
+		for (port = 0; port < PORTS_PER_RTA; port++, PortN++) {
+			unsigned short dest_port = port + 8;
+			u16 __iomem *TxPktP;
+			struct PKT __iomem *Pkt;
+
+			PortP = p->RIOPortp[PortN];
+
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			/*
+			 ** If RTA is not powered on, the tx packets will be
+			 ** unset, so go no further.
+			 */
+			if (!PortP->TxStart) {
+				rio_dprintk(RIO_DEBUG_ROUTE, "Tx pkts not set up yet\n");
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				break;
+			}
+
+			/*
+			 ** For the second slot of a 16 port RTA, the driver needs to
+			 ** sort out the phb to port mappings. The dest_unit for this
+			 ** group of 8 phbs is set to the dest_unit of the accompanying
+			 ** 8 port block. The dest_port of the second unit is set to
+			 ** be in the range 8-15 (i.e. 8 is added). Thus, for a 16 port
+			 ** RTA with IDs 5 and 6, traffic bound for port 6 of unit 6
+			 ** (being the second map ID) will be sent to dest_unit 5, port
+			 ** 14. When this RTA is deleted, dest_unit for ID 6 will be
+			 ** restored, and the dest_port will be reduced by 8.
+			 ** Transmit packets also have a destination field which needs
+			 ** adjusting in the same manner.
+			 ** Note that the unit/port bytes in 'dest' are swapped.
+			 ** We also need to adjust the phb and rup link numbers for the
+			 ** second block of 8 ttys.
+			 */
+			for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+				/*
+				 ** *TxPktP is the pointer to the transmit packet on the host
+				 ** card. This needs to be translated into a 32 bit pointer
+				 ** so it can be accessed from the driver.
+				 */
+				Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(TxPktP));
+
+				/*
+				 ** If the packet is used, reset it.
+				 */
+				Pkt = (struct PKT __iomem *) ((unsigned long) Pkt & ~PKT_IN_USE);
+				writeb(dest_unit, &Pkt->dest_unit);
+				writeb(dest_port, &Pkt->dest_port);
+			}
+			rio_dprintk(RIO_DEBUG_ROUTE, "phb dest: Old %x:%x New %x:%x\n", readw(&PortP->PhbP->destination) & 0xff, (readw(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);
+			writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);
+			writew(link, &PortP->PhbP->link);
+
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		}
+		/*
+		 ** Now make sure the range of ports to be serviced includes
+		 ** the 2nd 8 on this 16 port RTA.
+		 */
+		if (link > 3)
+			return;
+		if (((unit * 8) + 7) > readw(&HostP->LinkStrP[link].last_port)) {
+			rio_dprintk(RIO_DEBUG_ROUTE, "last port on host link %d: %d\n", link, (unit * 8) + 7);
+			writew((unit * 8) + 7, &HostP->LinkStrP[link].last_port);
+		}
+	}
+}
+
+/*
+** Check to see if the new disconnection has isolated this unit.
+** If it has, then invalidate all its link information, and tell
+** the world about it. This is done to ensure that the configurator
+** only gets up-to-date information about what is going on.
+*/
+static int RIOCheckIsolated(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
+{
+	unsigned long flags;
+	rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+	if (RIOCheck(HostP, UnitId)) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unit %d is NOT isolated\n", UnitId);
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+		return (0);
+	}
+
+	RIOIsolate(p, HostP, UnitId);
+	RIOSetChange(p);
+	rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	return 1;
+}
+
+/*
+** Invalidate all the link interconnectivity of this unit, and of
+** all the units attached to it. This will mean that the entire
+** subnet will re-introduce itself.
+*/
+static int RIOIsolate(struct rio_info *p, struct Host *HostP, unsigned int UnitId)
+{
+	unsigned int link, unit;
+
+	UnitId--;		/* this trick relies on the Unit Id being UNSIGNED! */
+
+	if (UnitId >= MAX_RUP)	/* dontcha just lurv unsigned maths! */
+		return (0);
+
+	if (HostP->Mapping[UnitId].Flags & BEEN_HERE)
+		return (0);
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	if (p->RIOPrintDisabled == DO_PRINT)
+		rio_dprintk(RIO_DEBUG_ROUTE, "RIOMesgIsolated %s", HostP->Mapping[UnitId].Name);
+
+	for (link = 0; link < LINKS_PER_UNIT; link++) {
+		unit = HostP->Mapping[UnitId].Topology[link].Unit;
+		HostP->Mapping[UnitId].Topology[link].Unit = ROUTE_DISCONNECT;
+		HostP->Mapping[UnitId].Topology[link].Link = NO_LINK;
+		RIOIsolate(p, HostP, unit);
+	}
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+	return 1;
+}
+
+static int RIOCheck(struct Host *HostP, unsigned int UnitId)
+{
+	unsigned char link;
+
+/* 	rio_dprint(RIO_DEBUG_ROUTE, ("Check to see if unit %d has a route to the host\n",UnitId)); */
+	rio_dprintk(RIO_DEBUG_ROUTE, "RIOCheck : UnitID = %d\n", UnitId);
+
+	if (UnitId == HOST_ID) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is NOT isolated - it IS the host!\n", UnitId)); */
+		return 1;
+	}
+
+	UnitId--;
+
+	if (UnitId >= MAX_RUP) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d - ignored.\n", UnitId)); */
+		return 0;
+	}
+
+	for (link = 0; link < LINKS_PER_UNIT; link++) {
+		if (HostP->Mapping[UnitId].Topology[link].Unit == HOST_ID) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected directly to host via link (%c).\n", 
+			   UnitId, 'A'+link)); */
+			return 1;
+		}
+	}
+
+	if (HostP->Mapping[UnitId].Flags & BEEN_HERE) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Been to Unit %d before - ignoring\n", UnitId)); */
+		return 0;
+	}
+
+	HostP->Mapping[UnitId].Flags |= BEEN_HERE;
+
+	for (link = 0; link < LINKS_PER_UNIT; link++) {
+		/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d check link (%c)\n", UnitId,'A'+link)); */
+		if (RIOCheck(HostP, HostP->Mapping[UnitId].Topology[link].Unit)) {
+			/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d is connected to something that knows the host via link (%c)\n", UnitId,link+'A')); */
+			HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+			return 1;
+		}
+	}
+
+	HostP->Mapping[UnitId].Flags &= ~BEEN_HERE;
+
+	/* rio_dprint(RIO_DEBUG_ROUTE, ("Unit %d DOESNT KNOW THE HOST!\n", UnitId)); */
+
+	return 0;
+}
+
+/*
+** Returns the type of unit (host, 16/8 port RTA)
+*/
+
+unsigned int GetUnitType(unsigned int Uniq)
+{
+	switch ((Uniq >> 28) & 0xf) {
+	case RIO_AT:
+	case RIO_MCA:
+	case RIO_EISA:
+	case RIO_PCI:
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Host\n");
+		return (TYPE_HOST);
+	case RIO_RTA_16:
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 16 port RTA\n");
+		return (TYPE_RTA16);
+	case RIO_RTA:
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: 8 port RTA\n");
+		return (TYPE_RTA8);
+	default:
+		rio_dprintk(RIO_DEBUG_ROUTE, "Unit type: Unrecognised\n");
+		return (99);
+	}
+}
+
+int RIOSetChange(struct rio_info *p)
+{
+	if (p->RIOQuickCheck != NOT_CHANGED)
+		return (0);
+	p->RIOQuickCheck = CHANGED;
+	if (p->RIOSignalProcess) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Send SIG-HUP");
+		/*
+		   psignal( RIOSignalProcess, SIGHUP );
+		 */
+	}
+	return (0);
+}
+
+static void RIOConCon(struct rio_info *p,
+		      struct Host *HostP,
+		      unsigned int FromId,
+		      unsigned int FromLink,
+		      unsigned int ToId,
+		      unsigned int ToLink,
+		      int Change)
+{
+	char *FromName;
+	char *FromType;
+	char *ToName;
+	char *ToType;
+	unsigned int tp;
+
+/*
+** 15.10.1998 ARG - ESIL 0759
+** (Part) fix for port being trashed when opened whilst RTA "disconnected"
+**
+** What's this doing in here anyway ?
+** It was causing the port to be 'unmapped' if opened whilst RTA "disconnected"
+**
+** 09.12.1998 ARG - ESIL 0776 - part fix
+** Okay, We've found out what this was all about now !
+** Someone had botched this to use RIOHalted to indicated the number of RTAs
+** 'disconnected'. The value in RIOHalted was then being used in the
+** 'RIO_QUICK_CHECK' ioctl. A none zero value indicating that a least one RTA
+** is 'disconnected'. The change was put in to satisfy a customer's needs.
+** Having taken this bit of code out 'RIO_QUICK_CHECK' now no longer works for
+** the customer.
+**
+    if (Change == CONNECT) {
+		if (p->RIOHalted) p->RIOHalted --;
+	 }
+	 else {
+		p->RIOHalted ++;
+	 }
+**
+** So - we need to implement it slightly differently - a new member of the
+** rio_info struct - RIORtaDisCons (RIO RTA connections) keeps track of RTA
+** connections and disconnections. 
+*/
+	if (Change == CONNECT) {
+		if (p->RIORtaDisCons)
+			p->RIORtaDisCons--;
+	} else {
+		p->RIORtaDisCons++;
+	}
+
+	if (p->RIOPrintDisabled == DONT_PRINT)
+		return;
+
+	if (FromId > ToId) {
+		tp = FromId;
+		FromId = ToId;
+		ToId = tp;
+		tp = FromLink;
+		FromLink = ToLink;
+		ToLink = tp;
+	}
+
+	FromName = FromId ? HostP->Mapping[FromId - 1].Name : HostP->Name;
+	FromType = FromId ? "RTA" : "HOST";
+	ToName = ToId ? HostP->Mapping[ToId - 1].Name : HostP->Name;
+	ToType = ToId ? "RTA" : "HOST";
+
+	rio_dprintk(RIO_DEBUG_ROUTE, "Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
+	printk(KERN_DEBUG "rio: Link between %s '%s' (%c) and %s '%s' (%c) %s.\n", FromType, FromName, 'A' + FromLink, ToType, ToName, 'A' + ToLink, (Change == CONNECT) ? "established" : "disconnected");
+}
+
+/*
+** RIORemoveFromSavedTable :
+**
+** Delete and RTA entry from the saved table given to us
+** by the configuration program.
+*/
+static int RIORemoveFromSavedTable(struct rio_info *p, struct Map *pMap)
+{
+	int entry;
+
+	/*
+	 ** We loop for all entries even after finding an entry and
+	 ** zeroing it because we may have two entries to delete if
+	 ** it's a 16 port RTA.
+	 */
+	for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+		if (p->RIOSavedTable[entry].RtaUniqueNum == pMap->RtaUniqueNum) {
+			memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map));
+		}
+	}
+	return 0;
+}
+
+
+/*
+** RIOCheckDisconnected :
+**
+** Scan the unit links to and return zero if the unit is completely
+** disconnected.
+*/
+static int RIOFreeDisconnected(struct rio_info *p, struct Host *HostP, int unit)
+{
+	int link;
+
+
+	rio_dprintk(RIO_DEBUG_ROUTE, "RIOFreeDisconnect unit %d\n", unit);
+	/*
+	 ** If the slot is tentative and does not belong to the
+	 ** second half of a 16 port RTA then scan to see if
+	 ** is disconnected.
+	 */
+	for (link = 0; link < LINKS_PER_UNIT; link++) {
+		if (HostP->Mapping[unit].Topology[link].Unit != ROUTE_DISCONNECT)
+			break;
+	}
+
+	/*
+	 ** If not all links are disconnected then we can forget about it.
+	 */
+	if (link < LINKS_PER_UNIT)
+		return 1;
+
+#ifdef NEED_TO_FIX_THIS
+	/* Ok so all the links are disconnected. But we may have only just
+	 ** made this slot tentative and not yet received a topology update.
+	 ** Lets check how long ago we made it tentative.
+	 */
+	rio_dprintk(RIO_DEBUG_ROUTE, "Just about to check LBOLT on entry %d\n", unit);
+	if (drv_getparm(LBOLT, (ulong_t *) & current_time))
+		rio_dprintk(RIO_DEBUG_ROUTE, "drv_getparm(LBOLT,....) Failed.\n");
+
+	elapse_time = current_time - TentTime[unit];
+	rio_dprintk(RIO_DEBUG_ROUTE, "elapse %d = current %d - tent %d (%d usec)\n", elapse_time, current_time, TentTime[unit], drv_hztousec(elapse_time));
+	if (drv_hztousec(elapse_time) < WAIT_TO_FINISH) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Skipping slot %d, not timed out yet %d\n", unit, drv_hztousec(elapse_time));
+		return 1;
+	}
+#endif
+
+	/*
+	 ** We have found an usable slot.
+	 ** If it is half of a 16 port RTA then delete the other half.
+	 */
+	if (HostP->Mapping[unit].ID2 != 0) {
+		int nOther = (HostP->Mapping[unit].ID2) - 1;
+
+		rio_dprintk(RIO_DEBUG_ROUTE, "RioFreedis second slot %d.\n", nOther);
+		memset(&HostP->Mapping[nOther], 0, sizeof(struct Map));
+	}
+	RIORemoveFromSavedTable(p, &HostP->Mapping[unit]);
+
+	return 0;
+}
+
+
+/*
+** RIOFindFreeID :
+**
+** This function scans the given host table for either one
+** or two free unit ID's.
+*/
+
+int RIOFindFreeID(struct rio_info *p, struct Host *HostP, unsigned int * pID1, unsigned int * pID2)
+{
+	int unit, tempID;
+
+	/*
+	 ** Initialise the ID's to MAX_RUP.
+	 ** We do this to make the loop for setting the ID's as simple as
+	 ** possible.
+	 */
+	*pID1 = MAX_RUP;
+	if (pID2 != NULL)
+		*pID2 = MAX_RUP;
+
+	/*
+	 ** Scan all entries of the host mapping table for free slots.
+	 ** We scan for free slots first and then if that is not successful
+	 ** we start all over again looking for tentative slots we can re-use.
+	 */
+	for (unit = 0; unit < MAX_RUP; unit++) {
+		rio_dprintk(RIO_DEBUG_ROUTE, "Scanning unit %d\n", unit);
+		/*
+		 ** If the flags are zero then the slot is empty.
+		 */
+		if (HostP->Mapping[unit].Flags == 0) {
+			rio_dprintk(RIO_DEBUG_ROUTE, "      This slot is empty.\n");
+			/*
+			 ** If we haven't allocated the first ID then do it now.
+			 */
+			if (*pID1 == MAX_RUP) {
+				rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for first unit %d\n", unit);
+				*pID1 = unit;
+
+				/*
+				 ** If the second ID is not needed then we can return
+				 ** now.
+				 */
+				if (pID2 == NULL)
+					return 0;
+			} else {
+				/*
+				 ** Allocate the second slot and return.
+				 */
+				rio_dprintk(RIO_DEBUG_ROUTE, "Make tentative entry for second unit %d\n", unit);
+				*pID2 = unit;
+				return 0;
+			}
+		}
+	}
+
+	/*
+	 ** If we manage to come out of the free slot loop then we
+	 ** need to start all over again looking for tentative slots
+	 ** that we can re-use.
+	 */
+	rio_dprintk(RIO_DEBUG_ROUTE, "Starting to scan for tentative slots\n");
+	for (unit = 0; unit < MAX_RUP; unit++) {
+		if (((HostP->Mapping[unit].Flags & SLOT_TENTATIVE) || (HostP->Mapping[unit].Flags == 0)) && !(HostP->Mapping[unit].Flags & RTA16_SECOND_SLOT)) {
+			rio_dprintk(RIO_DEBUG_ROUTE, "    Slot %d looks promising.\n", unit);
+
+			if (unit == *pID1) {
+				rio_dprintk(RIO_DEBUG_ROUTE, "    No it isn't, its the 1st half\n");
+				continue;
+			}
+
+			/*
+			 ** Slot is Tentative or Empty, but not a tentative second
+			 ** slot of a 16 porter.
+			 ** Attempt to free up this slot (and its parnter if
+			 ** it is a 16 port slot. The second slot will become
+			 ** empty after a call to RIOFreeDisconnected so thats why
+			 ** we look for empty slots above  as well).
+			 */
+			if (HostP->Mapping[unit].Flags != 0)
+				if (RIOFreeDisconnected(p, HostP, unit) != 0)
+					continue;
+			/*
+			 ** If we haven't allocated the first ID then do it now.
+			 */
+			if (*pID1 == MAX_RUP) {
+				rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative entry for first unit %d\n", unit);
+				*pID1 = unit;
+
+				/*
+				 ** Clear out this slot now that we intend to use it.
+				 */
+				memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
+
+				/*
+				 ** If the second ID is not needed then we can return
+				 ** now.
+				 */
+				if (pID2 == NULL)
+					return 0;
+			} else {
+				/*
+				 ** Allocate the second slot and return.
+				 */
+				rio_dprintk(RIO_DEBUG_ROUTE, "Grab tentative/empty  entry for second unit %d\n", unit);
+				*pID2 = unit;
+
+				/*
+				 ** Clear out this slot now that we intend to use it.
+				 */
+				memset(&HostP->Mapping[unit], 0, sizeof(struct Map));
+
+				/* At this point under the right(wrong?) conditions
+				 ** we may have a first unit ID being higher than the
+				 ** second unit ID. This is a bad idea if we are about
+				 ** to fill the slots with a 16 port RTA.
+				 ** Better check and swap them over.
+				 */
+
+				if (*pID1 > *pID2) {
+					rio_dprintk(RIO_DEBUG_ROUTE, "Swapping IDS %d %d\n", *pID1, *pID2);
+					tempID = *pID1;
+					*pID1 = *pID2;
+					*pID2 = tempID;
+				}
+				return 0;
+			}
+		}
+	}
+
+	/*
+	 ** If we manage to get to the end of the second loop then we
+	 ** can give up and return a failure.
+	 */
+	return 1;
+}
+
+
+/*
+** The link switch scenario.
+**
+** Rta Wun (A) is connected to Tuw (A).
+** The tables are all up to date, and the system is OK.
+**
+** If Wun (A) is now moved to Wun (B) before Wun (A) can
+** become disconnected, then the follow happens:
+**
+** Tuw (A) spots the change of unit:link at the other end
+** of its link and Tuw sends a topology packet reflecting
+** the change: Tuw (A) now disconnected from Wun (A), and
+** this is closely followed by a packet indicating that 
+** Tuw (A) is now connected to Wun (B).
+**
+** Wun (B) will spot that it has now become connected, and
+** Wun will send a topology packet, which indicates that
+** both Wun (A) and Wun (B) is connected to Tuw (A).
+**
+** Eventually Wun (A) realises that it is now disconnected
+** and Wun will send out a topology packet indicating that
+** Wun (A) is now disconnected.
+*/
diff --git a/drivers/staging/generic_serial/rio/riospace.h b/drivers/staging/generic_serial/rio/riospace.h
new file mode 100644
index 0000000..ffb31d4
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riospace.h
@@ -0,0 +1,154 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riospace.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:13
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)riospace.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_riospace_h__
+#define __rio_riospace_h__
+
+#define	RIO_LOCATOR_LEN	16
+#define	MAX_RIO_BOARDS	4
+
+/*
+** DONT change this file. At all. Unless you can rebuild the entire
+** device driver, which you probably can't, then the rest of the
+** driver won't see any changes you make here. So don't make any.
+** In particular, it won't be able to see changes to RIO_SLOTS
+*/
+
+struct Conf {
+	char Locator[24];
+	unsigned int StartupTime;
+	unsigned int SlowCook;
+	unsigned int IntrPollTime;
+	unsigned int BreakInterval;
+	unsigned int Timer;
+	unsigned int RtaLoadBase;
+	unsigned int HostLoadBase;
+	unsigned int XpHz;
+	unsigned int XpCps;
+	char *XpOn;
+	char *XpOff;
+	unsigned int MaxXpCps;
+	unsigned int MinXpCps;
+	unsigned int SpinCmds;
+	unsigned int FirstAddr;
+	unsigned int LastAddr;
+	unsigned int BufferSize;
+	unsigned int LowWater;
+	unsigned int LineLength;
+	unsigned int CmdTime;
+};
+
+/*
+**	Board types - these MUST correspond to product codes!
+*/
+#define	RIO_EMPTY	0x0
+#define	RIO_EISA	0x3
+#define	RIO_RTA_16	0x9
+#define	RIO_AT		0xA
+#define	RIO_MCA		0xB
+#define	RIO_PCI		0xD
+#define	RIO_RTA		0xE
+
+/*
+**	Board data structure. This is used for configuration info
+*/
+struct Brd {
+	unsigned char Type;	/* RIO_EISA, RIO_MCA, RIO_AT, RIO_EMPTY... */
+	unsigned char Ivec;	/* POLLED or ivec number */
+	unsigned char Mode;	/* Control stuff, see below */
+};
+
+struct Board {
+	char Locator[RIO_LOCATOR_LEN];
+	int NumSlots;
+	struct Brd Boards[MAX_RIO_BOARDS];
+};
+
+#define	BOOT_FROM_LINK		0x00
+#define	BOOT_FROM_RAM		0x01
+#define	EXTERNAL_BUS_OFF	0x00
+#define	EXTERNAL_BUS_ON		0x02
+#define	INTERRUPT_DISABLE	0x00
+#define	INTERRUPT_ENABLE	0x04
+#define	BYTE_OPERATION		0x00
+#define	WORD_OPERATION		0x08
+#define	POLLED			INTERRUPT_DISABLE
+#define	IRQ_15			(0x00 | INTERRUPT_ENABLE)
+#define	IRQ_12			(0x10 | INTERRUPT_ENABLE)
+#define	IRQ_11			(0x20 | INTERRUPT_ENABLE)
+#define	IRQ_9			(0x30 | INTERRUPT_ENABLE)
+#define	SLOW_LINKS		0x00
+#define	FAST_LINKS		0x40
+#define	SLOW_AT_BUS		0x00
+#define	FAST_AT_BUS		0x80
+#define	SLOW_PCI_TP		0x00
+#define	FAST_PCI_TP		0x80
+/*
+**	Debug levels
+*/
+#define	DBG_NONE	0x00000000
+
+#define	DBG_INIT	0x00000001
+#define	DBG_OPEN	0x00000002
+#define	DBG_CLOSE	0x00000004
+#define	DBG_IOCTL	0x00000008
+
+#define	DBG_READ	0x00000010
+#define	DBG_WRITE	0x00000020
+#define	DBG_INTR	0x00000040
+#define	DBG_PROC	0x00000080
+
+#define	DBG_PARAM	0x00000100
+#define	DBG_CMD		0x00000200
+#define	DBG_XPRINT	0x00000400
+#define	DBG_POLL	0x00000800
+
+#define	DBG_DAEMON	0x00001000
+#define	DBG_FAIL	0x00002000
+#define DBG_MODEM	0x00004000
+#define	DBG_LIST	0x00008000
+
+#define	DBG_ROUTE	0x00010000
+#define DBG_UTIL        0x00020000
+#define DBG_BOOT	0x00040000
+#define DBG_BUFFER	0x00080000
+
+#define	DBG_MON		0x00100000
+#define DBG_SPECIAL     0x00200000
+#define	DBG_VPIX	0x00400000
+#define	DBG_FLUSH	0x00800000
+
+#define	DBG_QENABLE	0x01000000
+
+#define	DBG_ALWAYS	0x80000000
+
+#endif				/* __rio_riospace_h__ */
diff --git a/drivers/staging/generic_serial/rio/riotable.c b/drivers/staging/generic_serial/rio/riotable.c
new file mode 100644
index 0000000..3d15802
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riotable.c
@@ -0,0 +1,941 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riotable.c
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotable.c	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+#include "protsts.h"
+
+/*
+** A configuration table has been loaded. It is now up to us
+** to sort it out and use the information contained therein.
+*/
+int RIONewTable(struct rio_info *p)
+{
+	int Host, Host1, Host2, NameIsUnique, Entry, SubEnt;
+	struct Map *MapP;
+	struct Map *HostMapP;
+	struct Host *HostP;
+
+	char *cptr;
+
+	/*
+	 ** We have been sent a new table to install. We need to break
+	 ** it down into little bits and spread it around a bit to see
+	 ** what we have got.
+	 */
+	/*
+	 ** Things to check:
+	 ** (things marked 'xx' aren't checked any more!)
+	 ** (1) That there are no booted Hosts/RTAs out there.
+	 ** (2) That the names are properly formed
+	 ** (3) That blank entries really are.
+	 ** xx (4)      That hosts mentioned in the table actually exist. xx
+	 ** (5) That the IDs are unique (per host).
+	 ** (6) That host IDs are zero
+	 ** (7) That port numbers are valid
+	 ** (8) That port numbers aren't duplicated
+	 ** (9) That names aren't duplicated
+	 ** xx (10) That hosts that actually exist are mentioned in the table. xx
+	 */
+	rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(1)\n");
+	if (p->RIOSystemUp) {	/* (1) */
+		p->RIOError.Error = HOST_HAS_ALREADY_BEEN_BOOTED;
+		return -EBUSY;
+	}
+
+	p->RIOError.Error = NOTHING_WRONG_AT_ALL;
+	p->RIOError.Entry = -1;
+	p->RIOError.Other = -1;
+
+	for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+		MapP = &p->RIOConnectTable[Entry];
+		if ((MapP->Flags & RTA16_SECOND_SLOT) == 0) {
+			rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(2)\n");
+			cptr = MapP->Name;	/* (2) */
+			cptr[MAX_NAME_LEN - 1] = '\0';
+			if (cptr[0] == '\0') {
+				memcpy(MapP->Name, MapP->RtaUniqueNum ? "RTA	NN" : "HOST NN", 8);
+				MapP->Name[5] = '0' + Entry / 10;
+				MapP->Name[6] = '0' + Entry % 10;
+			}
+			while (*cptr) {
+				if (*cptr < ' ' || *cptr > '~') {
+					p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+					p->RIOError.Entry = Entry;
+					return -ENXIO;
+				}
+				cptr++;
+			}
+		}
+
+		/*
+		 ** If the entry saved was a tentative entry then just forget
+		 ** about it.
+		 */
+		if (MapP->Flags & SLOT_TENTATIVE) {
+			MapP->HostUniqueNum = 0;
+			MapP->RtaUniqueNum = 0;
+			continue;
+		}
+
+		rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(3)\n");
+		if (!MapP->RtaUniqueNum && !MapP->HostUniqueNum) {	/* (3) */
+			if (MapP->ID || MapP->SysPort || MapP->Flags) {
+				rio_dprintk(RIO_DEBUG_TABLE, "%s pretending to be empty but isn't\n", MapP->Name);
+				p->RIOError.Error = TABLE_ENTRY_ISNT_PROPERLY_NULL;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			rio_dprintk(RIO_DEBUG_TABLE, "!RIO: Daemon: test (3) passes\n");
+			continue;
+		}
+
+		rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(4)\n");
+		for (Host = 0; Host < p->RIONumHosts; Host++) {	/* (4) */
+			if (p->RIOHosts[Host].UniqueNum == MapP->HostUniqueNum) {
+				HostP = &p->RIOHosts[Host];
+				/*
+				 ** having done the lookup, we don't really want to do
+				 ** it again, so hang the host number in a safe place
+				 */
+				MapP->Topology[0].Unit = Host;
+				break;
+			}
+		}
+
+		if (Host >= p->RIONumHosts) {
+			rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has unknown host unique number 0x%x\n", MapP->Name, MapP->HostUniqueNum);
+			MapP->HostUniqueNum = 0;
+			/* MapP->RtaUniqueNum   = 0; */
+			/* MapP->ID                     = 0; */
+			/* MapP->Flags           = 0; */
+			/* MapP->SysPort                 = 0; */
+			/* MapP->Name[0]                 = 0; */
+			continue;
+		}
+
+		rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(5)\n");
+		if (MapP->RtaUniqueNum) {	/* (5) */
+			if (!MapP->ID) {
+				rio_dprintk(RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an ID of zero!\n", MapP->Name);
+				p->RIOError.Error = ZERO_RTA_ID;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			if (MapP->ID > MAX_RUP) {
+				rio_dprintk(RIO_DEBUG_TABLE, "RIO: RTA %s has been allocated an invalid ID %d\n", MapP->Name, MapP->ID);
+				p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			for (SubEnt = 0; SubEnt < Entry; SubEnt++) {
+				if (MapP->HostUniqueNum == p->RIOConnectTable[SubEnt].HostUniqueNum && MapP->ID == p->RIOConnectTable[SubEnt].ID) {
+					rio_dprintk(RIO_DEBUG_TABLE, "Dupl. ID number allocated to RTA %s and RTA %s\n", MapP->Name, p->RIOConnectTable[SubEnt].Name);
+					p->RIOError.Error = DUPLICATED_RTA_ID;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return -ENXIO;
+				}
+				/*
+				 ** If the RtaUniqueNum is the same, it may be looking at both
+				 ** entries for a 16 port RTA, so check the ids
+				 */
+				if ((MapP->RtaUniqueNum == p->RIOConnectTable[SubEnt].RtaUniqueNum)
+				    && (MapP->ID2 != p->RIOConnectTable[SubEnt].ID)) {
+					rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", MapP->Name);
+					rio_dprintk(RIO_DEBUG_TABLE, "RTA %s has duplicate unique number\n", p->RIOConnectTable[SubEnt].Name);
+					p->RIOError.Error = DUPLICATE_UNIQUE_NUMBER;
+					p->RIOError.Entry = Entry;
+					p->RIOError.Other = SubEnt;
+					return -ENXIO;
+				}
+			}
+			rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(7a)\n");
+			/* (7a) */
+			if ((MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA)) {
+				rio_dprintk(RIO_DEBUG_TABLE, "TTY Port number %d-RTA %s is not a multiple of %d!\n", (int) MapP->SysPort, MapP->Name, PORTS_PER_RTA);
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(7b)\n");
+			/* (7b) */
+			if ((MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS)) {
+				rio_dprintk(RIO_DEBUG_TABLE, "TTY Port number %d for RTA %s is too big\n", (int) MapP->SysPort, MapP->Name);
+				p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			for (SubEnt = 0; SubEnt < Entry; SubEnt++) {
+				if (p->RIOConnectTable[SubEnt].Flags & RTA16_SECOND_SLOT)
+					continue;
+				if (p->RIOConnectTable[SubEnt].RtaUniqueNum) {
+					rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(8)\n");
+					/* (8) */
+					if ((MapP->SysPort != NO_PORT) && (MapP->SysPort == p->RIOConnectTable[SubEnt].SysPort)) {
+						rio_dprintk(RIO_DEBUG_TABLE, "RTA %s:same TTY port # as RTA %s (%d)\n", MapP->Name, p->RIOConnectTable[SubEnt].Name, (int) MapP->SysPort);
+						p->RIOError.Error = TTY_NUMBER_IN_USE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return -ENXIO;
+					}
+					rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(9)\n");
+					if (strcmp(MapP->Name, p->RIOConnectTable[SubEnt].Name) == 0 && !(MapP->Flags & RTA16_SECOND_SLOT)) {	/* (9) */
+						rio_dprintk(RIO_DEBUG_TABLE, "RTA name %s used twice\n", MapP->Name);
+						p->RIOError.Error = NAME_USED_TWICE;
+						p->RIOError.Entry = Entry;
+						p->RIOError.Other = SubEnt;
+						return -ENXIO;
+					}
+				}
+			}
+		} else {	/* (6) */
+			rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: entering(6)\n");
+			if (MapP->ID) {
+				rio_dprintk(RIO_DEBUG_TABLE, "RIO:HOST %s has been allocated ID that isn't zero!\n", MapP->Name);
+				p->RIOError.Error = HOST_ID_NOT_ZERO;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+			if (MapP->SysPort != NO_PORT) {
+				rio_dprintk(RIO_DEBUG_TABLE, "RIO: HOST %s has been allocated port numbers!\n", MapP->Name);
+				p->RIOError.Error = HOST_SYSPORT_BAD;
+				p->RIOError.Entry = Entry;
+				return -ENXIO;
+			}
+		}
+	}
+
+	/*
+	 ** wow! if we get here then it's a goody!
+	 */
+
+	/*
+	 ** Zero the (old) entries for each host...
+	 */
+	for (Host = 0; Host < RIO_HOSTS; Host++) {
+		for (Entry = 0; Entry < MAX_RUP; Entry++) {
+			memset(&p->RIOHosts[Host].Mapping[Entry], 0, sizeof(struct Map));
+		}
+		memset(&p->RIOHosts[Host].Name[0], 0, sizeof(p->RIOHosts[Host].Name));
+	}
+
+	/*
+	 ** Copy in the new table entries
+	 */
+	for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+		rio_dprintk(RIO_DEBUG_TABLE, "RIONewTable: Copy table for Host entry %d\n", Entry);
+		MapP = &p->RIOConnectTable[Entry];
+
+		/*
+		 ** Now, if it is an empty slot ignore it!
+		 */
+		if (MapP->HostUniqueNum == 0)
+			continue;
+
+		/*
+		 ** we saved the host number earlier, so grab it back
+		 */
+		HostP = &p->RIOHosts[MapP->Topology[0].Unit];
+
+		/*
+		 ** If it is a host, then we only need to fill in the name field.
+		 */
+		if (MapP->ID == 0) {
+			rio_dprintk(RIO_DEBUG_TABLE, "Host entry found. Name %s\n", MapP->Name);
+			memcpy(HostP->Name, MapP->Name, MAX_NAME_LEN);
+			continue;
+		}
+
+		/*
+		 ** Its an RTA entry, so fill in the host mapping entries for it
+		 ** and the port mapping entries. Notice that entry zero is for
+		 ** ID one.
+		 */
+		HostMapP = &HostP->Mapping[MapP->ID - 1];
+
+		if (MapP->Flags & SLOT_IN_USE) {
+			rio_dprintk(RIO_DEBUG_TABLE, "Rta entry found. Name %s\n", MapP->Name);
+			/*
+			 ** structure assign, then sort out the bits we shouldn't have done
+			 */
+			*HostMapP = *MapP;
+
+			HostMapP->Flags = SLOT_IN_USE;
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+			RIOReMapPorts(p, HostP, HostMapP);
+		} else {
+			rio_dprintk(RIO_DEBUG_TABLE, "TENTATIVE Rta entry found. Name %s\n", MapP->Name);
+		}
+	}
+
+	for (Entry = 0; Entry < TOTAL_MAP_ENTRIES; Entry++) {
+		p->RIOSavedTable[Entry] = p->RIOConnectTable[Entry];
+	}
+
+	for (Host = 0; Host < p->RIONumHosts; Host++) {
+		for (SubEnt = 0; SubEnt < LINKS_PER_UNIT; SubEnt++) {
+			p->RIOHosts[Host].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+			p->RIOHosts[Host].Topology[SubEnt].Link = NO_LINK;
+		}
+		for (Entry = 0; Entry < MAX_RUP; Entry++) {
+			for (SubEnt = 0; SubEnt < LINKS_PER_UNIT; SubEnt++) {
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Unit = ROUTE_DISCONNECT;
+				p->RIOHosts[Host].Mapping[Entry].Topology[SubEnt].Link = NO_LINK;
+			}
+		}
+		if (!p->RIOHosts[Host].Name[0]) {
+			memcpy(p->RIOHosts[Host].Name, "HOST 1", 7);
+			p->RIOHosts[Host].Name[5] += Host;
+		}
+		/*
+		 ** Check that default name assigned is unique.
+		 */
+		Host1 = Host;
+		NameIsUnique = 0;
+		while (!NameIsUnique) {
+			NameIsUnique = 1;
+			for (Host2 = 0; Host2 < p->RIONumHosts; Host2++) {
+				if (Host2 == Host)
+					continue;
+				if (strcmp(p->RIOHosts[Host].Name, p->RIOHosts[Host2].Name)
+				    == 0) {
+					NameIsUnique = 0;
+					Host1++;
+					if (Host1 >= p->RIONumHosts)
+						Host1 = 0;
+					p->RIOHosts[Host].Name[5] = '1' + Host1;
+				}
+			}
+		}
+		/*
+		 ** Rename host if name already used.
+		 */
+		if (Host1 != Host) {
+			rio_dprintk(RIO_DEBUG_TABLE, "Default name %s already used\n", p->RIOHosts[Host].Name);
+			memcpy(p->RIOHosts[Host].Name, "HOST 1", 7);
+			p->RIOHosts[Host].Name[5] += Host1;
+		}
+		rio_dprintk(RIO_DEBUG_TABLE, "Assigning default name %s\n", p->RIOHosts[Host].Name);
+	}
+	return 0;
+}
+
+/*
+** User process needs the config table - build it from first
+** principles.
+**
+*	FIXME: SMP locking
+*/
+int RIOApel(struct rio_info *p)
+{
+	int Host;
+	int link;
+	int Rup;
+	int Next = 0;
+	struct Map *MapP;
+	struct Host *HostP;
+	unsigned long flags;
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Generating a table to return to config.rio\n");
+
+	memset(&p->RIOConnectTable[0], 0, sizeof(struct Map) * TOTAL_MAP_ENTRIES);
+
+	for (Host = 0; Host < RIO_HOSTS; Host++) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Processing host %d\n", Host);
+		HostP = &p->RIOHosts[Host];
+		rio_spin_lock_irqsave(&HostP->HostLock, flags);
+
+		MapP = &p->RIOConnectTable[Next++];
+		MapP->HostUniqueNum = HostP->UniqueNum;
+		if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+			rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+			continue;
+		}
+		MapP->RtaUniqueNum = 0;
+		MapP->ID = 0;
+		MapP->Flags = SLOT_IN_USE;
+		MapP->SysPort = NO_PORT;
+		for (link = 0; link < LINKS_PER_UNIT; link++)
+			MapP->Topology[link] = HostP->Topology[link];
+		memcpy(MapP->Name, HostP->Name, MAX_NAME_LEN);
+		for (Rup = 0; Rup < MAX_RUP; Rup++) {
+			if (HostP->Mapping[Rup].Flags & (SLOT_IN_USE | SLOT_TENTATIVE)) {
+				p->RIOConnectTable[Next] = HostP->Mapping[Rup];
+				if (HostP->Mapping[Rup].Flags & SLOT_IN_USE)
+					p->RIOConnectTable[Next].Flags |= SLOT_IN_USE;
+				if (HostP->Mapping[Rup].Flags & SLOT_TENTATIVE)
+					p->RIOConnectTable[Next].Flags |= SLOT_TENTATIVE;
+				if (HostP->Mapping[Rup].Flags & RTA16_SECOND_SLOT)
+					p->RIOConnectTable[Next].Flags |= RTA16_SECOND_SLOT;
+				Next++;
+			}
+		}
+		rio_spin_unlock_irqrestore(&HostP->HostLock, flags);
+	}
+	return 0;
+}
+
+/*
+** config.rio has taken a dislike to one of the gross maps entries.
+** if the entry is suitably inactive, then we can gob on it and remove
+** it from the table.
+*/
+int RIODeleteRta(struct rio_info *p, struct Map *MapP)
+{
+	int host, entry, port, link;
+	int SysPort;
+	struct Host *HostP;
+	struct Map *HostMapP;
+	struct Port *PortP;
+	int work_done = 0;
+	unsigned long lock_flags, sem_flags;
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Delete entry on host %x, rta %x\n", MapP->HostUniqueNum, MapP->RtaUniqueNum);
+
+	for (host = 0; host < p->RIONumHosts; host++) {
+		HostP = &p->RIOHosts[host];
+
+		rio_spin_lock_irqsave(&HostP->HostLock, lock_flags);
+
+		if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
+			rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+			continue;
+		}
+
+		for (entry = 0; entry < MAX_RUP; entry++) {
+			if (MapP->RtaUniqueNum == HostP->Mapping[entry].RtaUniqueNum) {
+				HostMapP = &HostP->Mapping[entry];
+				rio_dprintk(RIO_DEBUG_TABLE, "Found entry offset %d on host %s\n", entry, HostP->Name);
+
+				/*
+				 ** Check all four links of the unit are disconnected
+				 */
+				for (link = 0; link < LINKS_PER_UNIT; link++) {
+					if (HostMapP->Topology[link].Unit != ROUTE_DISCONNECT) {
+						rio_dprintk(RIO_DEBUG_TABLE, "Entry is in use and cannot be deleted!\n");
+						p->RIOError.Error = UNIT_IS_IN_USE;
+						rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+						return -EBUSY;
+					}
+				}
+				/*
+				 ** Slot has been allocated, BUT not booted/routed/
+				 ** connected/selected or anything else-ed
+				 */
+				SysPort = HostMapP->SysPort;
+
+				if (SysPort != NO_PORT) {
+					for (port = SysPort; port < SysPort + PORTS_PER_RTA; port++) {
+						PortP = p->RIOPortp[port];
+						rio_dprintk(RIO_DEBUG_TABLE, "Unmap port\n");
+
+						rio_spin_lock_irqsave(&PortP->portSem, sem_flags);
+
+						PortP->Mapped = 0;
+
+						if (PortP->State & (RIO_MOPEN | RIO_LOPEN)) {
+
+							rio_dprintk(RIO_DEBUG_TABLE, "Gob on port\n");
+							PortP->TxBufferIn = PortP->TxBufferOut = 0;
+							/* What should I do 
+							   wakeup( &PortP->TxBufferIn );
+							   wakeup( &PortP->TxBufferOut);
+							 */
+							PortP->InUse = NOT_INUSE;
+							/* What should I do 
+							   wakeup( &PortP->InUse );
+							   signal(PortP->TtyP->t_pgrp,SIGKILL);
+							   ttyflush(PortP->TtyP,(FREAD|FWRITE));
+							 */
+							PortP->State |= RIO_CLOSING | RIO_DELETED;
+						}
+
+						/*
+						 ** For the second slot of a 16 port RTA, the
+						 ** driver needs to reset the changes made to
+						 ** the phb to port mappings in RIORouteRup.
+						 */
+						if (PortP->SecondBlock) {
+							u16 dest_unit = HostMapP->ID;
+							u16 dest_port = port - SysPort;
+							u16 __iomem *TxPktP;
+							struct PKT __iomem *Pkt;
+
+							for (TxPktP = PortP->TxStart; TxPktP <= PortP->TxEnd; TxPktP++) {
+								/*
+								 ** *TxPktP is the pointer to the
+								 ** transmit packet on the host card.
+								 ** This needs to be translated into
+								 ** a 32 bit pointer so it can be
+								 ** accessed from the driver.
+								 */
+								Pkt = (struct PKT __iomem *) RIO_PTR(HostP->Caddr, readw(&*TxPktP));
+								rio_dprintk(RIO_DEBUG_TABLE, "Tx packet (%x) destination: Old %x:%x New %x:%x\n", readw(TxPktP), readb(&Pkt->dest_unit), readb(&Pkt->dest_port), dest_unit, dest_port);
+								writew(dest_unit, &Pkt->dest_unit);
+								writew(dest_port, &Pkt->dest_port);
+							}
+							rio_dprintk(RIO_DEBUG_TABLE, "Port %d phb destination: Old %x:%x New %x:%x\n", port, readb(&PortP->PhbP->destination) & 0xff, (readb(&PortP->PhbP->destination) >> 8) & 0xff, dest_unit, dest_port);
+							writew(dest_unit + (dest_port << 8), &PortP->PhbP->destination);
+						}
+						rio_spin_unlock_irqrestore(&PortP->portSem, sem_flags);
+					}
+				}
+				rio_dprintk(RIO_DEBUG_TABLE, "Entry nulled.\n");
+				memset(HostMapP, 0, sizeof(struct Map));
+				work_done++;
+			}
+		}
+		rio_spin_unlock_irqrestore(&HostP->HostLock, lock_flags);
+	}
+
+	/* XXXXX lock me up */
+	for (entry = 0; entry < TOTAL_MAP_ENTRIES; entry++) {
+		if (p->RIOSavedTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) {
+			memset(&p->RIOSavedTable[entry], 0, sizeof(struct Map));
+			work_done++;
+		}
+		if (p->RIOConnectTable[entry].RtaUniqueNum == MapP->RtaUniqueNum) {
+			memset(&p->RIOConnectTable[entry], 0, sizeof(struct Map));
+			work_done++;
+		}
+	}
+	if (work_done)
+		return 0;
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Couldn't find entry to be deleted\n");
+	p->RIOError.Error = COULDNT_FIND_ENTRY;
+	return -ENXIO;
+}
+
+int RIOAssignRta(struct rio_info *p, struct Map *MapP)
+{
+	int host;
+	struct Map *HostMapP;
+	char *sptr;
+	int link;
+
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Assign entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum, MapP->RtaUniqueNum, MapP->ID, (int) MapP->SysPort);
+
+	if ((MapP->ID != (u16) - 1) && ((int) MapP->ID < (int) 1 || (int) MapP->ID > MAX_RUP)) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Bad ID in map entry!\n");
+		p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+	if (MapP->RtaUniqueNum == 0) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Rta Unique number zero!\n");
+		p->RIOError.Error = RTA_UNIQUE_NUMBER_ZERO;
+		return -EINVAL;
+	}
+	if ((MapP->SysPort != NO_PORT) && (MapP->SysPort % PORTS_PER_RTA)) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Port %d not multiple of %d!\n", (int) MapP->SysPort, PORTS_PER_RTA);
+		p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+	if ((MapP->SysPort != NO_PORT) && (MapP->SysPort >= RIO_PORTS)) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Port %d not valid!\n", (int) MapP->SysPort);
+		p->RIOError.Error = TTY_NUMBER_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	/*
+	 ** Copy the name across to the map entry.
+	 */
+	MapP->Name[MAX_NAME_LEN - 1] = '\0';
+	sptr = MapP->Name;
+	while (*sptr) {
+		if (*sptr < ' ' || *sptr > '~') {
+			rio_dprintk(RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n");
+			p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+			return -EINVAL;
+		}
+		sptr++;
+	}
+
+	for (host = 0; host < p->RIONumHosts; host++) {
+		if (MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum) {
+			if ((p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING) {
+				p->RIOError.Error = HOST_NOT_RUNNING;
+				return -ENXIO;
+			}
+
+			/*
+			 ** Now we have a host we need to allocate an ID
+			 ** if the entry does not already have one.
+			 */
+			if (MapP->ID == (u16) - 1) {
+				int nNewID;
+
+				rio_dprintk(RIO_DEBUG_TABLE, "Attempting to get a new ID for rta \"%s\"\n", MapP->Name);
+				/*
+				 ** The idea here is to allow RTA's to be assigned
+				 ** before they actually appear on the network.
+				 ** This allows the addition of RTA's without having
+				 ** to plug them in.
+				 ** What we do is:
+				 **  - Find a free ID and allocate it to the RTA.
+				 **  - If this map entry is the second half of a
+				 **    16 port entry then find the other half and
+				 **    make sure the 2 cross reference each other.
+				 */
+				if (RIOFindFreeID(p, &p->RIOHosts[host], &nNewID, NULL) != 0) {
+					p->RIOError.Error = COULDNT_FIND_ENTRY;
+					return -EBUSY;
+				}
+				MapP->ID = (u16) nNewID + 1;
+				rio_dprintk(RIO_DEBUG_TABLE, "Allocated ID %d for this new RTA.\n", MapP->ID);
+				HostMapP = &p->RIOHosts[host].Mapping[nNewID];
+				HostMapP->RtaUniqueNum = MapP->RtaUniqueNum;
+				HostMapP->HostUniqueNum = MapP->HostUniqueNum;
+				HostMapP->ID = MapP->ID;
+				for (link = 0; link < LINKS_PER_UNIT; link++) {
+					HostMapP->Topology[link].Unit = ROUTE_DISCONNECT;
+					HostMapP->Topology[link].Link = NO_LINK;
+				}
+				if (MapP->Flags & RTA16_SECOND_SLOT) {
+					int unit;
+
+					for (unit = 0; unit < MAX_RUP; unit++)
+						if (p->RIOHosts[host].Mapping[unit].RtaUniqueNum == MapP->RtaUniqueNum)
+							break;
+					if (unit == MAX_RUP) {
+						p->RIOError.Error = COULDNT_FIND_ENTRY;
+						return -EBUSY;
+					}
+					HostMapP->Flags |= RTA16_SECOND_SLOT;
+					HostMapP->ID2 = MapP->ID2 = p->RIOHosts[host].Mapping[unit].ID;
+					p->RIOHosts[host].Mapping[unit].ID2 = MapP->ID;
+					rio_dprintk(RIO_DEBUG_TABLE, "Cross referenced id %d to ID %d.\n", MapP->ID, p->RIOHosts[host].Mapping[unit].ID);
+				}
+			}
+
+			HostMapP = &p->RIOHosts[host].Mapping[MapP->ID - 1];
+
+			if (HostMapP->Flags & SLOT_IN_USE) {
+				rio_dprintk(RIO_DEBUG_TABLE, "Map table slot for ID %d is already in use.\n", MapP->ID);
+				p->RIOError.Error = ID_ALREADY_IN_USE;
+				return -EBUSY;
+			}
+
+			/*
+			 ** Assign the sys ports and the name, and mark the slot as
+			 ** being in use.
+			 */
+			HostMapP->SysPort = MapP->SysPort;
+			if ((MapP->Flags & RTA16_SECOND_SLOT) == 0)
+				memcpy(HostMapP->Name, MapP->Name, MAX_NAME_LEN);
+			HostMapP->Flags = SLOT_IN_USE | RTA_BOOTED;
+#ifdef NEED_TO_FIX
+			RIO_SV_BROADCAST(p->RIOHosts[host].svFlags[MapP->ID - 1]);
+#endif
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				HostMapP->Flags |= RTA16_SECOND_SLOT;
+
+			RIOReMapPorts(p, &p->RIOHosts[host], HostMapP);
+			/*
+			 ** Adjust 2nd block of 8 phbs
+			 */
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				RIOFixPhbs(p, &p->RIOHosts[host], HostMapP->ID - 1);
+
+			if (HostMapP->SysPort != NO_PORT) {
+				if (HostMapP->SysPort < p->RIOFirstPortsBooted)
+					p->RIOFirstPortsBooted = HostMapP->SysPort;
+				if (HostMapP->SysPort > p->RIOLastPortsBooted)
+					p->RIOLastPortsBooted = HostMapP->SysPort;
+			}
+			if (MapP->Flags & RTA16_SECOND_SLOT)
+				rio_dprintk(RIO_DEBUG_TABLE, "Second map of RTA %s added to configuration\n", p->RIOHosts[host].Mapping[MapP->ID2 - 1].Name);
+			else
+				rio_dprintk(RIO_DEBUG_TABLE, "RTA %s added to configuration\n", MapP->Name);
+			return 0;
+		}
+	}
+	p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+	rio_dprintk(RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum);
+	return -ENXIO;
+}
+
+
+int RIOReMapPorts(struct rio_info *p, struct Host *HostP, struct Map *HostMapP)
+{
+	struct Port *PortP;
+	unsigned int SubEnt;
+	unsigned int HostPort;
+	unsigned int SysPort;
+	u16 RtaType;
+	unsigned long flags;
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Mapping sysport %d to id %d\n", (int) HostMapP->SysPort, HostMapP->ID);
+
+	/*
+	 ** We need to tell the UnixRups which sysport the rup corresponds to
+	 */
+	HostP->UnixRups[HostMapP->ID - 1].BaseSysPort = HostMapP->SysPort;
+
+	if (HostMapP->SysPort == NO_PORT)
+		return (0);
+
+	RtaType = GetUnitType(HostMapP->RtaUniqueNum);
+	rio_dprintk(RIO_DEBUG_TABLE, "Mapping sysport %d-%d\n", (int) HostMapP->SysPort, (int) HostMapP->SysPort + PORTS_PER_RTA - 1);
+
+	/*
+	 ** now map each of its eight ports
+	 */
+	for (SubEnt = 0; SubEnt < PORTS_PER_RTA; SubEnt++) {
+		rio_dprintk(RIO_DEBUG_TABLE, "subent = %d, HostMapP->SysPort = %d\n", SubEnt, (int) HostMapP->SysPort);
+		SysPort = HostMapP->SysPort + SubEnt;	/* portnumber within system */
+		/* portnumber on host */
+
+		HostPort = (HostMapP->ID - 1) * PORTS_PER_RTA + SubEnt;
+
+		rio_dprintk(RIO_DEBUG_TABLE, "c1 p = %p, p->rioPortp = %p\n", p, p->RIOPortp);
+		PortP = p->RIOPortp[SysPort];
+		rio_dprintk(RIO_DEBUG_TABLE, "Map port\n");
+
+		/*
+		 ** Point at all the real neat data structures
+		 */
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		PortP->HostP = HostP;
+		PortP->Caddr = HostP->Caddr;
+
+		/*
+		 ** The PhbP cannot be filled in yet
+		 ** unless the host has been booted
+		 */
+		if ((HostP->Flags & RUN_STATE) == RC_RUNNING) {
+			struct PHB __iomem *PhbP = PortP->PhbP = &HostP->PhbP[HostPort];
+			PortP->TxAdd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_add));
+			PortP->TxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_start));
+			PortP->TxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->tx_end));
+			PortP->RxRemove = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_remove));
+			PortP->RxStart = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_start));
+			PortP->RxEnd = (u16 __iomem *) RIO_PTR(HostP->Caddr, readw(&PhbP->rx_end));
+		} else
+			PortP->PhbP = NULL;
+
+		/*
+		 ** port related flags
+		 */
+		PortP->HostPort = HostPort;
+		/*
+		 ** For each part of a 16 port RTA, RupNum is ID - 1.
+		 */
+		PortP->RupNum = HostMapP->ID - 1;
+		if (HostMapP->Flags & RTA16_SECOND_SLOT) {
+			PortP->ID2 = HostMapP->ID2 - 1;
+			PortP->SecondBlock = 1;
+		} else {
+			PortP->ID2 = 0;
+			PortP->SecondBlock = 0;
+		}
+		PortP->RtaUniqueNum = HostMapP->RtaUniqueNum;
+
+		/*
+		 ** If the port was already mapped then thats all we need to do.
+		 */
+		if (PortP->Mapped) {
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			continue;
+		} else
+			HostMapP->Flags &= ~RTA_NEWBOOT;
+
+		PortP->State = 0;
+		PortP->Config = 0;
+		/*
+		 ** Check out the module type - if it is special (read only etc.)
+		 ** then we need to set flags in the PortP->Config.
+		 ** Note: For 16 port RTA, all ports are of the same type.
+		 */
+		if (RtaType == TYPE_RTA16) {
+			PortP->Config |= p->RIOModuleTypes[HostP->UnixRups[HostMapP->ID - 1].ModTypes].Flags[SubEnt % PORTS_PER_MODULE];
+		} else {
+			if (SubEnt < PORTS_PER_MODULE)
+				PortP->Config |= p->RIOModuleTypes[LONYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+			else
+				PortP->Config |= p->RIOModuleTypes[HINYBLE(HostP->UnixRups[HostMapP->ID - 1].ModTypes)].Flags[SubEnt % PORTS_PER_MODULE];
+		}
+
+		/*
+		 ** more port related flags
+		 */
+		PortP->PortState = 0;
+		PortP->ModemLines = 0;
+		PortP->ModemState = 0;
+		PortP->CookMode = COOK_WELL;
+		PortP->ParamSem = 0;
+		PortP->FlushCmdBodge = 0;
+		PortP->WflushFlag = 0;
+		PortP->MagicFlags = 0;
+		PortP->Lock = 0;
+		PortP->Store = 0;
+		PortP->FirstOpen = 1;
+
+		/*
+		 ** Buffers 'n things
+		 */
+		PortP->RxDataStart = 0;
+		PortP->Cor2Copy = 0;
+		PortP->Name = &HostMapP->Name[0];
+		PortP->statsGather = 0;
+		PortP->txchars = 0;
+		PortP->rxchars = 0;
+		PortP->opens = 0;
+		PortP->closes = 0;
+		PortP->ioctls = 0;
+		if (PortP->TxRingBuffer)
+			memset(PortP->TxRingBuffer, 0, p->RIOBufferSize);
+		else if (p->RIOBufferSize) {
+			PortP->TxRingBuffer = kzalloc(p->RIOBufferSize, GFP_KERNEL);
+		}
+		PortP->TxBufferOut = 0;
+		PortP->TxBufferIn = 0;
+		PortP->Debug = 0;
+		/*
+		 ** LastRxTgl stores the state of the rx toggle bit for this
+		 ** port, to be compared with the state of the next pkt received.
+		 ** If the same, we have received the same rx pkt from the RTA
+		 ** twice. Initialise to a value not equal to PHB_RX_TGL or 0.
+		 */
+		PortP->LastRxTgl = ~(u8) PHB_RX_TGL;
+
+		/*
+		 ** and mark the port as usable
+		 */
+		PortP->Mapped = 1;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	}
+	if (HostMapP->SysPort < p->RIOFirstPortsMapped)
+		p->RIOFirstPortsMapped = HostMapP->SysPort;
+	if (HostMapP->SysPort > p->RIOLastPortsMapped)
+		p->RIOLastPortsMapped = HostMapP->SysPort;
+
+	return 0;
+}
+
+int RIOChangeName(struct rio_info *p, struct Map *MapP)
+{
+	int host;
+	struct Map *HostMapP;
+	char *sptr;
+
+	rio_dprintk(RIO_DEBUG_TABLE, "Change name entry on host %x, rta %x, ID %d, Sysport %d\n", MapP->HostUniqueNum, MapP->RtaUniqueNum, MapP->ID, (int) MapP->SysPort);
+
+	if (MapP->ID > MAX_RUP) {
+		rio_dprintk(RIO_DEBUG_TABLE, "Bad ID in map entry!\n");
+		p->RIOError.Error = ID_NUMBER_OUT_OF_RANGE;
+		return -EINVAL;
+	}
+
+	MapP->Name[MAX_NAME_LEN - 1] = '\0';
+	sptr = MapP->Name;
+
+	while (*sptr) {
+		if (*sptr < ' ' || *sptr > '~') {
+			rio_dprintk(RIO_DEBUG_TABLE, "Name entry contains non-printing characters!\n");
+			p->RIOError.Error = BAD_CHARACTER_IN_NAME;
+			return -EINVAL;
+		}
+		sptr++;
+	}
+
+	for (host = 0; host < p->RIONumHosts; host++) {
+		if (MapP->HostUniqueNum == p->RIOHosts[host].UniqueNum) {
+			if ((p->RIOHosts[host].Flags & RUN_STATE) != RC_RUNNING) {
+				p->RIOError.Error = HOST_NOT_RUNNING;
+				return -ENXIO;
+			}
+			if (MapP->ID == 0) {
+				memcpy(p->RIOHosts[host].Name, MapP->Name, MAX_NAME_LEN);
+				return 0;
+			}
+
+			HostMapP = &p->RIOHosts[host].Mapping[MapP->ID - 1];
+
+			if (HostMapP->RtaUniqueNum != MapP->RtaUniqueNum) {
+				p->RIOError.Error = RTA_NUMBER_WRONG;
+				return -ENXIO;
+			}
+			memcpy(HostMapP->Name, MapP->Name, MAX_NAME_LEN);
+			return 0;
+		}
+	}
+	p->RIOError.Error = UNKNOWN_HOST_NUMBER;
+	rio_dprintk(RIO_DEBUG_TABLE, "Unknown host %x\n", MapP->HostUniqueNum);
+	return -ENXIO;
+}
diff --git a/drivers/staging/generic_serial/rio/riotty.c b/drivers/staging/generic_serial/rio/riotty.c
new file mode 100644
index 0000000..8a90393
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/riotty.c
@@ -0,0 +1,654 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: riotty.c
+**	SID		: 1.3
+**	Last Modified	: 11/6/98 10:33:47
+**	Retrieved	: 11/6/98 10:33:50
+**
+**  ident @(#)riotty.c	1.3
+**
+** -----------------------------------------------------------------------------
+*/
+
+#define __EXPLICIT_DEF_H__
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/string.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/termios.h>
+
+#include <linux/serial.h>
+
+#include <linux/generic_serial.h>
+
+
+#include "linux_compat.h"
+#include "rio_linux.h"
+#include "pkt.h"
+#include "daemon.h"
+#include "rio.h"
+#include "riospace.h"
+#include "cmdpkt.h"
+#include "map.h"
+#include "rup.h"
+#include "port.h"
+#include "riodrvr.h"
+#include "rioinfo.h"
+#include "func.h"
+#include "errors.h"
+#include "pci.h"
+
+#include "parmmap.h"
+#include "unixrup.h"
+#include "board.h"
+#include "host.h"
+#include "phb.h"
+#include "link.h"
+#include "cmdblk.h"
+#include "route.h"
+#include "cirrus.h"
+#include "rioioctl.h"
+#include "param.h"
+
+static void RIOClearUp(struct Port *PortP);
+
+/* Below belongs in func.h */
+int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);
+
+
+extern struct rio_info *p;
+
+
+int riotopen(struct tty_struct *tty, struct file *filp)
+{
+	unsigned int SysPort;
+	int repeat_this = 250;
+	struct Port *PortP;	/* pointer to the port structure */
+	unsigned long flags;
+	int retval = 0;
+
+	func_enter();
+
+	/* Make sure driver_data is NULL in case the rio isn't booted jet. Else gs_close
+	   is going to oops.
+	 */
+	tty->driver_data = NULL;
+
+	SysPort = rio_minor(tty);
+
+	if (p->RIOFailed) {
+		rio_dprintk(RIO_DEBUG_TTY, "System initialisation failed\n");
+		func_exit();
+		return -ENXIO;
+	}
+
+	rio_dprintk(RIO_DEBUG_TTY, "port open SysPort %d (mapped:%d)\n", SysPort, p->RIOPortp[SysPort]->Mapped);
+
+	/*
+	 ** Validate that we have received a legitimate request.
+	 ** Currently, just check that we are opening a port on
+	 ** a host card that actually exists, and that the port
+	 ** has been mapped onto a host.
+	 */
+	if (SysPort >= RIO_PORTS) {	/* out of range ? */
+		rio_dprintk(RIO_DEBUG_TTY, "Illegal port number %d\n", SysPort);
+		func_exit();
+		return -ENXIO;
+	}
+
+	/*
+	 ** Grab pointer to the port stucture
+	 */
+	PortP = p->RIOPortp[SysPort];	/* Get control struc */
+	rio_dprintk(RIO_DEBUG_TTY, "PortP: %p\n", PortP);
+	if (!PortP->Mapped) {	/* we aren't mapped yet! */
+		/*
+		 ** The system doesn't know which RTA this port
+		 ** corresponds to.
+		 */
+		rio_dprintk(RIO_DEBUG_TTY, "port not mapped into system\n");
+		func_exit();
+		return -ENXIO;
+	}
+
+	tty->driver_data = PortP;
+
+	PortP->gs.port.tty = tty;
+	PortP->gs.port.count++;
+
+	rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt);
+
+	retval = gs_init_port(&PortP->gs);
+	if (retval) {
+		PortP->gs.port.count--;
+		return -ENXIO;
+	}
+	/*
+	 ** If the host hasn't been booted yet, then
+	 ** fail
+	 */
+	if ((PortP->HostP->Flags & RUN_STATE) != RC_RUNNING) {
+		rio_dprintk(RIO_DEBUG_TTY, "Host not running\n");
+		func_exit();
+		return -ENXIO;
+	}
+
+	/*
+	 ** If the RTA has not booted yet and the user has choosen to block
+	 ** until the RTA is present then we must spin here waiting for
+	 ** the RTA to boot.
+	 */
+	/* I find the above code a bit hairy. I find the below code
+	   easier to read and shorter. Now, if it works too that would
+	   be great... -- REW 
+	 */
+	rio_dprintk(RIO_DEBUG_TTY, "Checking if RTA has booted... \n");
+	while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) {
+		if (!PortP->WaitUntilBooted) {
+			rio_dprintk(RIO_DEBUG_TTY, "RTA never booted\n");
+			func_exit();
+			return -ENXIO;
+		}
+
+		/* Under Linux you'd normally use a wait instead of this
+		   busy-waiting. I'll stick with the old implementation for
+		   now. --REW
+		 */
+		if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+			rio_dprintk(RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n");
+			func_exit();
+			return -EINTR;
+		}
+		if (repeat_this-- <= 0) {
+			rio_dprintk(RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n");
+			func_exit();
+			return -EIO;
+		}
+	}
+	rio_dprintk(RIO_DEBUG_TTY, "RTA has been booted\n");
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	if (p->RIOHalted) {
+		goto bombout;
+	}
+
+	/*
+	 ** If the port is in the final throws of being closed,
+	 ** we should wait here (politely), waiting
+	 ** for it to finish, so that it doesn't close us!
+	 */
+	while ((PortP->State & RIO_CLOSING) && !p->RIOHalted) {
+		rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n");
+		if (repeat_this-- <= 0) {
+			rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
+			RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+			retval = -EINTR;
+			goto bombout;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if (!PortP->Mapped) {
+		rio_dprintk(RIO_DEBUG_TTY, "Port unmapped while closing!\n");
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		retval = -ENXIO;
+		func_exit();
+		return retval;
+	}
+
+	if (p->RIOHalted) {
+		goto bombout;
+	}
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,
+** we need to make sure that the flags are clear when the port is opened.
+*/
+	/* Uh? Suppose I turn these on and then another process opens
+	   the port again? The flags get cleared! Not good. -- REW */
+	if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+		PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW);
+	}
+
+	if (!(PortP->firstOpen)) {	/* First time ? */
+		rio_dprintk(RIO_DEBUG_TTY, "First open for this port\n");
+
+
+		PortP->firstOpen++;
+		PortP->CookMode = 0;	/* XXX RIOCookMode(tp); */
+		PortP->InUse = NOT_INUSE;
+
+		/* Tentative fix for bug PR27. Didn't work. */
+		/* PortP->gs.xmit_cnt = 0; */
+
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+		/* Someone explain to me why this delay/config is
+		   here. If I read the docs correctly the "open"
+		   command piggybacks the parameters immediately.
+		   -- REW */
+		RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+		/*
+		 ** wait for the port to be not closed.
+		 */
+		while (!(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted) {
+			rio_dprintk(RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n", PortP->PortState);
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n");
+				RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+				func_exit();
+				return -EINTR;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		}
+
+		if (p->RIOHalted) {
+			retval = -EIO;
+		      bombout:
+			/*                    RIOClearUp( PortP ); */
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			return retval;
+		}
+		rio_dprintk(RIO_DEBUG_TTY, "PORT_ISOPEN found\n");
+	}
+	rio_dprintk(RIO_DEBUG_TTY, "Modem - test for carrier\n");
+	/*
+	 ** ACTION
+	 ** insert test for carrier here. -- ???
+	 ** I already see that test here. What's the deal? -- REW
+	 */
+	if ((PortP->gs.port.tty->termios->c_cflag & CLOCAL) ||
+			(PortP->ModemState & RIOC_MSVR1_CD)) {
+		rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
+		/*
+		   tp->tm.c_state |= CARR_ON;
+		   wakeup((caddr_t) &tp->tm.c_canq);
+		 */
+		PortP->State |= RIO_CARR_ON;
+		wake_up_interruptible(&PortP->gs.port.open_wait);
+	} else {	/* no carrier - wait for DCD */
+			/*
+		   while (!(PortP->gs.port.tty->termios->c_state & CARR_ON) &&
+		   !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted )
+		 */
+		while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) {
+				rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort);
+			/*
+			   PortP->gs.port.tty->termios->c_state |= WOPEN;
+			 */
+			PortP->State |= RIO_WOPEN;
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				/*
+				 ** ACTION: verify that this is a good thing
+				 ** to do here. -- ???
+				 ** I think it's OK. -- REW
+				 */
+				rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort);
+				RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+				/*
+				   tp->tm.c_state &= ~WOPEN;
+				 */
+				PortP->State &= ~RIO_WOPEN;
+				rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+				func_exit();
+				return -EINTR;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		}
+		PortP->State &= ~RIO_WOPEN;
+	}
+	if (p->RIOHalted)
+		goto bombout;
+	rio_dprintk(RIO_DEBUG_TTY, "Setting RIO_MOPEN\n");
+	PortP->State |= RIO_MOPEN;
+
+	if (p->RIOHalted)
+		goto bombout;
+
+	rio_dprintk(RIO_DEBUG_TTY, "high level open done\n");
+
+	/*
+	 ** Count opens for port statistics reporting
+	 */
+	if (PortP->statsGather)
+		PortP->opens++;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprintk(RIO_DEBUG_TTY, "Returning from open\n");
+	func_exit();
+	return 0;
+}
+
+/*
+** RIOClose the port.
+** The operating system thinks that this is last close for the device.
+** As there are two interfaces to the port (Modem and tty), we need to
+** check that both are closed before we close the device.
+*/
+int riotclose(void *ptr)
+{
+	struct Port *PortP = ptr;	/* pointer to the port structure */
+	int deleted = 0;
+	int try = -1;		/* Disable the timeouts by setting them to -1 */
+	int repeat_this = -1;	/* Congrats to those having 15 years of
+				   uptime! (You get to break the driver.) */
+	unsigned long end_time;
+	struct tty_struct *tty;
+	unsigned long flags;
+	int rv = 0;
+
+	rio_dprintk(RIO_DEBUG_TTY, "port close SysPort %d\n", PortP->PortNum);
+
+	/* PortP = p->RIOPortp[SysPort]; */
+	rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP);
+	/* tp = PortP->TtyP; *//* Get tty */
+	tty = PortP->gs.port.tty;
+	rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty);
+
+	if (PortP->gs.closing_wait)
+		end_time = jiffies + PortP->gs.closing_wait;
+	else
+		end_time = jiffies + MAX_SCHEDULE_TIMEOUT;
+
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	 ** Setting this flag will make any process trying to open
+	 ** this port block until we are complete closing it.
+	 */
+	PortP->State |= RIO_CLOSING;
+
+	if ((PortP->State & RIO_DELETED)) {
+		rio_dprintk(RIO_DEBUG_TTY, "Close on deleted RTA\n");
+		deleted = 1;
+	}
+
+	if (p->RIOHalted) {
+		RIOClearUp(PortP);
+		rv = -EIO;
+		goto close_end;
+	}
+
+	rio_dprintk(RIO_DEBUG_TTY, "Clear bits\n");
+	/*
+	 ** clear the open bits for this device
+	 */
+	PortP->State &= ~RIO_MOPEN;
+	PortP->State &= ~RIO_CARR_ON;
+	PortP->ModemState &= ~RIOC_MSVR1_CD;
+	/*
+	 ** If the device was open as both a Modem and a tty line
+	 ** then we need to wimp out here, as the port has not really
+	 ** been finally closed (gee, whizz!) The test here uses the
+	 ** bit for the OTHER mode of operation, to see if THAT is
+	 ** still active!
+	 */
+	if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+		/*
+		 ** The port is still open for the other task -
+		 ** return, pretending that we are still active.
+		 */
+		rio_dprintk(RIO_DEBUG_TTY, "Channel %d still open !\n", PortP->PortNum);
+		PortP->State &= ~RIO_CLOSING;
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return -EIO;
+	}
+
+	rio_dprintk(RIO_DEBUG_TTY, "Closing down - everything must go!\n");
+
+	PortP->State &= ~RIO_DYNOROD;
+
+	/*
+	 ** This is where we wait for the port
+	 ** to drain down before closing. Bye-bye....
+	 ** (We never meant to do this)
+	 */
+	rio_dprintk(RIO_DEBUG_TTY, "Timeout 1 starts\n");
+
+	if (!deleted)
+		while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut)) {
+			if (repeat_this-- <= 0) {
+				rv = -EINTR;
+				rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
+				RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+				goto close_end;
+			}
+			rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
+			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+			if (RIODelay_ni(PortP, HUNDRED_MS * 10) == RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
+				rv = -EINTR;
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				goto close_end;
+			}
+			rio_spin_lock_irqsave(&PortP->portSem, flags);
+		}
+
+	PortP->TxBufferIn = PortP->TxBufferOut = 0;
+	repeat_this = 0xff;
+
+	PortP->InUse = 0;
+	if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
+		/*
+		 ** The port has been re-opened for the other task -
+		 ** return, pretending that we are still active.
+		 */
+		rio_dprintk(RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum);
+		PortP->State &= ~RIO_CLOSING;
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (PortP->firstOpen)
+			PortP->firstOpen--;
+		return -EIO;
+	}
+
+	if (p->RIOHalted) {
+		RIOClearUp(PortP);
+		goto close_end;
+	}
+
+	/* Can't call RIOShortCommand with the port locked. */
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+
+	if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) {
+		RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+		goto close_end;
+	}
+
+	if (!deleted)
+		while (try && (PortP->PortState & PORT_ISOPEN)) {
+			try--;
+			if (time_after(jiffies, end_time)) {
+				rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
+				RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+				break;
+			}
+			rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);
+
+			if (p->RIOHalted) {
+				RIOClearUp(PortP);
+				rio_spin_lock_irqsave(&PortP->portSem, flags);
+				goto close_end;
+			}
+			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
+				rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
+				RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
+				break;
+			}
+		}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+	rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);
+
+	/* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */
+
+/*
+** 15.10.1998 ARG - ESIL 0761 part fix
+** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened.
+*/
+	PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW);
+
+	/*
+	 ** Count opens for port statistics reporting
+	 */
+	if (PortP->statsGather)
+		PortP->closes++;
+
+close_end:
+	/* XXX: Why would a "DELETED" flag be reset here? I'd have
+	   thought that a "deleted" flag means that the port was
+	   permanently gone, but here we can make it reappear by it
+	   being in close during the "deletion".
+	 */
+	PortP->State &= ~(RIO_CLOSING | RIO_DELETED);
+	if (PortP->firstOpen)
+		PortP->firstOpen--;
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	rio_dprintk(RIO_DEBUG_TTY, "Return from close\n");
+	return rv;
+}
+
+
+
+static void RIOClearUp(struct Port *PortP)
+{
+	rio_dprintk(RIO_DEBUG_TTY, "RIOHalted set\n");
+	PortP->Config = 0;	/* Direct semaphore */
+	PortP->PortState = 0;
+	PortP->firstOpen = 0;
+	PortP->FlushCmdBodge = 0;
+	PortP->ModemState = PortP->CookMode = 0;
+	PortP->Mapped = 0;
+	PortP->WflushFlag = 0;
+	PortP->MagicFlags = 0;
+	PortP->RxDataStart = 0;
+	PortP->TxBufferIn = 0;
+	PortP->TxBufferOut = 0;
+}
+
+/*
+** Put a command onto a port.
+** The PortPointer, command, length and arg are passed.
+** The len is the length *inclusive* of the command byte,
+** and so for a command that takes no data, len==1.
+** The arg is a single byte, and is only used if len==2.
+** Other values of len aren't allowed, and will cause
+** a panic.
+*/
+int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg)
+{
+	struct PKT __iomem *PacketP;
+	int retries = 20;	/* at 10 per second -> 2 seconds */
+	unsigned long flags;
+
+	rio_dprintk(RIO_DEBUG_TTY, "entering shortcommand.\n");
+
+	if (PortP->State & RIO_DELETED) {
+		rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
+		return RIO_FAIL;
+	}
+	rio_spin_lock_irqsave(&PortP->portSem, flags);
+
+	/*
+	 ** If the port is in use for pre-emptive command, then wait for it to
+	 ** be free again.
+	 */
+	while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted) {
+		rio_dprintk(RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", retries);
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+			return RIO_FAIL;
+		}
+		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+	if (PortP->State & RIO_DELETED) {
+		rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	while (!can_add_transmit(&PacketP, PortP) && !p->RIOHalted) {
+		rio_dprintk(RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries);
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		if (retries-- <= 0) {
+			rio_dprintk(RIO_DEBUG_TTY, "out of tries. Failing\n");
+			return RIO_FAIL;
+		}
+		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
+			return RIO_FAIL;
+		}
+		rio_spin_lock_irqsave(&PortP->portSem, flags);
+	}
+
+	if (p->RIOHalted) {
+		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+		return RIO_FAIL;
+	}
+
+	/*
+	 ** set the command byte and the argument byte
+	 */
+	writeb(command, &PacketP->data[0]);
+
+	if (len == 2)
+		writeb(arg, &PacketP->data[1]);
+
+	/*
+	 ** set the length of the packet and set the command bit.
+	 */
+	writeb(PKT_CMD_BIT | len, &PacketP->len);
+
+	add_transmit(PortP);
+	/*
+	 ** Count characters transmitted for port statistics reporting
+	 */
+	if (PortP->statsGather)
+		PortP->txchars += len;
+
+	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
+	return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL;
+}
+
+
diff --git a/drivers/staging/generic_serial/rio/route.h b/drivers/staging/generic_serial/rio/route.h
new file mode 100644
index 0000000..46e9637
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/route.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+ *******                                                              *******
+ *******                 R O U T E     H E A D E R
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra / Jeremy Rolls
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _route_h
+#define _route_h
+
+#define MAX_LINKS 4
+#define MAX_NODES 17		/* Maximum nodes in a subnet */
+#define NODE_BYTES ((MAX_NODES / 8) + 1)	/* Number of bytes needed for
+						   1 bit per node */
+#define ROUTE_DATA_SIZE  (NODE_BYTES + 2)	/* Number of bytes for complete
+						   info about cost etc. */
+#define ROUTES_PER_PACKET ((PKT_MAX_DATA_LEN -2)/ ROUTE_DATA_SIZE)
+					      /* Number of nodes we can squeeze
+					         into one packet */
+#define MAX_TOPOLOGY_PACKETS (MAX_NODES / ROUTES_PER_PACKET + 1)
+/************************************************
+ * Define the types of command for the ROUTE RUP.
+ ************************************************/
+#define ROUTE_REQUEST    0	/* Request an ID */
+#define ROUTE_FOAD       1	/* Kill the RTA */
+#define ROUTE_ALREADY    2	/* ID given already */
+#define ROUTE_USED       3	/* All ID's used */
+#define ROUTE_ALLOCATE   4	/* Here it is */
+#define ROUTE_REQ_TOP    5	/* I bet you didn't expect....
+				   the Topological Inquisition */
+#define ROUTE_TOPOLOGY   6	/* Topology request answered FD */
+/*******************************************************************
+ * Define the Route Map Structure
+ *
+ * The route map gives a pointer to a Link Structure to use.
+ * This allows Disconnected Links to be checked quickly
+ ******************************************************************/
+typedef struct COST_ROUTE COST_ROUTE;
+struct COST_ROUTE {
+	unsigned char cost;	/* Cost down this link */
+	unsigned char route[NODE_BYTES];	/* Nodes through this route */
+};
+
+typedef struct ROUTE_STR ROUTE_STR;
+struct ROUTE_STR {
+	COST_ROUTE cost_route[MAX_LINKS];
+	/* cost / route for this link */
+	ushort favoured;	/* favoured link */
+};
+
+
+#define NO_LINK            (short) 5	/* Link unattached */
+#define ROUTE_NO_ID        (short) 100	/* No Id */
+#define ROUTE_DISCONNECT   (ushort) 0xff	/* Not connected */
+#define ROUTE_INTERCONNECT (ushort) 0x40	/* Sub-net interconnect */
+
+
+#define SYNC_RUP         (ushort) 255
+#define COMMAND_RUP      (ushort) 254
+#define ERROR_RUP        (ushort) 253
+#define POLL_RUP         (ushort) 252
+#define BOOT_RUP         (ushort) 251
+#define ROUTE_RUP        (ushort) 250
+#define STATUS_RUP       (ushort) 249
+#define POWER_RUP        (ushort) 248
+
+#define HIGHEST_RUP      (ushort) 255	/* Set to Top one */
+#define LOWEST_RUP       (ushort) 248	/* Set to bottom one */
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/rup.h b/drivers/staging/generic_serial/rio/rup.h
new file mode 100644
index 0000000..4ae90cb
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/rup.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+ *******                                                              *******
+ *******               R U P   S T R U C T U R E
+ *******                                                              *******
+ ****************************************************************************
+
+ Author  : Ian Nandhra
+ Date    :
+
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+
+ Version : 0.01
+
+
+                            Mods
+ ----------------------------------------------------------------------------
+  Date     By                Description
+ ----------------------------------------------------------------------------
+
+ ***************************************************************************/
+
+#ifndef _rup_h
+#define _rup_h 1
+
+#define MAX_RUP          ((short) 16)
+#define PKTS_PER_RUP     ((short) 2)	/* They are always used in pairs */
+
+/*************************************************
+ * Define all the  packet request stuff
+ ************************************************/
+#define TX_RUP_INACTIVE          0	/* Nothing to transmit */
+#define TX_PACKET_READY          1	/* Transmit packet ready */
+#define TX_LOCK_RUP              2	/* Transmit side locked */
+
+#define RX_RUP_INACTIVE          0	/* Nothing received */
+#define RX_PACKET_READY          1	/* Packet received */
+
+#define RUP_NO_OWNER             0xff	/* RUP not owned by any process */
+
+struct RUP {
+	u16 txpkt;		/* Outgoing packet */
+	u16 rxpkt;		/* Incoming packet */
+	u16 link;		/* Which link to send down? */
+	u8 rup_dest_unit[2];	/* Destination unit */
+	u16 handshake;		/* For handshaking */
+	u16 timeout;		/* Timeout */
+	u16 status;		/* Status */
+	u16 txcontrol;		/* Transmit control */
+	u16 rxcontrol;		/* Receive control */
+};
+
+#endif
+
+/*********** end of file ***********/
diff --git a/drivers/staging/generic_serial/rio/unixrup.h b/drivers/staging/generic_serial/rio/unixrup.h
new file mode 100644
index 0000000..7abf0cb
--- /dev/null
+++ b/drivers/staging/generic_serial/rio/unixrup.h
@@ -0,0 +1,51 @@
+/*
+** -----------------------------------------------------------------------------
+**
+**  Perle Specialix driver for Linux
+**  Ported from existing RIO Driver for SCO sources.
+ *
+ *  (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK.
+ *
+ *      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.
+**
+**	Module		: unixrup.h
+**	SID		: 1.2
+**	Last Modified	: 11/6/98 11:34:20
+**	Retrieved	: 11/6/98 11:34:22
+**
+**  ident @(#)unixrup.h	1.2
+**
+** -----------------------------------------------------------------------------
+*/
+
+#ifndef __rio_unixrup_h__
+#define __rio_unixrup_h__
+
+/*
+**    UnixRup data structure. This contains pointers to actual RUPs on the
+**    host card, and all the command/boot control stuff.
+*/
+struct UnixRup {
+	struct CmdBlk *CmdsWaitingP;	/* Commands waiting to be done */
+	struct CmdBlk *CmdPendingP;	/* The command currently being sent */
+	struct RUP __iomem *RupP;	/* the Rup to send it to */
+	unsigned int Id;		/* Id number */
+	unsigned int BaseSysPort;	/* SysPort of first tty on this RTA */
+	unsigned int ModTypes;		/* Modules on this RTA */
+	spinlock_t RupLock;	/* Lock structure for MPX */
+	/*    struct lockb     RupLock;	*//* Lock structure for MPX */
+};
+
+#endif				/* __rio_unixrup_h__ */
diff --git a/drivers/staging/generic_serial/ser_a2232.c b/drivers/staging/generic_serial/ser_a2232.c
new file mode 100644
index 0000000..3f47c2e
--- /dev/null
+++ b/drivers/staging/generic_serial/ser_a2232.c
@@ -0,0 +1,831 @@
+/* drivers/char/ser_a2232.c */
+
+/* $Id: ser_a2232.c,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/* Linux serial driver for the Amiga A2232 board */
+
+/* This driver is MAINTAINED. Before applying any changes, please contact
+ * the author.
+ */
+
+/* Copyright (c) 2000-2001 Enver Haase    <ehaase@inf.fu-berlin.de>
+ *                   alias The A2232 driver project <A2232@gmx.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.
+ *
+ */
+/***************************** Documentation ************************/
+/*
+ * This driver is in EXPERIMENTAL state. That means I could not find
+ * someone with five A2232 boards with 35 ports running at 19200 bps
+ * at the same time and test the machine's behaviour.
+ * However, I know that you can performance-tweak this driver (see
+ * the source code).
+ * One thing to consider is the time this driver consumes during the
+ * Amiga's vertical blank interrupt. Everything that is to be done
+ * _IS DONE_ when entering the vertical blank interrupt handler of
+ * this driver.
+ * However, it would be more sane to only do the job for only ONE card
+ * instead of ALL cards at a time; or, more generally, to handle only
+ * SOME ports instead of ALL ports at a time.
+ * However, as long as no-one runs into problems I guess I shouldn't
+ * change the driver as it runs fine for me :) .
+ *
+ * Version history of this file:
+ * 0.4	Resolved licensing issues.
+ * 0.3	Inclusion in the Linux/m68k tree, small fixes.
+ * 0.2	Added documentation, minor typo fixes.
+ * 0.1	Initial release.
+ *
+ * TO DO:
+ * -	Handle incoming BREAK events. I guess "Stevens: Advanced
+ *	Programming in the UNIX(R) Environment" is a good reference
+ *	on what is to be done.
+ * -	When installing as a module, don't simply 'printk' text, but
+ *	send it to the TTY used by the user.
+ *
+ * THANKS TO:
+ * -	Jukka Marin (65EC02 code).
+ * -	The other NetBSD developers on whose A2232 driver I had a
+ *	pretty close look. However, I didn't copy any code so it
+ *	is okay to put my code under the GPL and include it into
+ *	Linux.
+ */
+/***************************** End of Documentation *****************/
+
+/***************************** Defines ******************************/
+/*
+ * Enables experimental 115200 (normal) 230400 (turbo) baud rate.
+ * The A2232 specification states it can only operate at speeds up to
+ * 19200 bits per second, and I was not able to send a file via
+ * "sz"/"rz" and a null-modem cable from one A2232 port to another
+ * at 115200 bits per second.
+ * However, this might work for you.
+ */
+#undef A2232_SPEEDHACK
+/*
+ * Default is not to use RTS/CTS so you could be talked to death.
+ */
+#define A2232_SUPPRESS_RTSCTS_WARNING
+/************************* End of Defines ***************************/
+
+/***************************** Includes *****************************/
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+
+#include <asm/setup.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <linux/mutex.h>
+
+#include <linux/delay.h>
+
+#include <linux/serial.h>
+#include <linux/generic_serial.h>
+#include <linux/tty_flip.h>
+
+#include "ser_a2232.h"
+#include "ser_a2232fw.h"
+/************************* End of Includes **************************/
+
+/***************************** Prototypes ***************************/
+/* The interrupt service routine */
+static irqreturn_t a2232_vbl_inter(int irq, void *data);
+/* Initialize the port structures */
+static void a2232_init_portstructs(void);
+/* Initialize and register TTY drivers. */
+/* returns 0 IFF successful */
+static int a2232_init_drivers(void); 
+
+/* BEGIN GENERIC_SERIAL PROTOTYPES */
+static void a2232_disable_tx_interrupts(void *ptr);
+static void a2232_enable_tx_interrupts(void *ptr);
+static void a2232_disable_rx_interrupts(void *ptr);
+static void a2232_enable_rx_interrupts(void *ptr);
+static int  a2232_carrier_raised(struct tty_port *port);
+static void a2232_shutdown_port(void *ptr);
+static int  a2232_set_real_termios(void *ptr);
+static int  a2232_chars_in_buffer(void *ptr);
+static void a2232_close(void *ptr);
+static void a2232_hungup(void *ptr);
+/* static void a2232_getserial (void *ptr, struct serial_struct *sp); */
+/* END GENERIC_SERIAL PROTOTYPES */
+
+/* Functions that the TTY driver struct expects */
+static int  a2232_ioctl(struct tty_struct *tty,
+				unsigned int cmd, unsigned long arg);
+static void a2232_throttle(struct tty_struct *tty);
+static void a2232_unthrottle(struct tty_struct *tty);
+static int  a2232_open(struct tty_struct * tty, struct file * filp);
+/************************* End of Prototypes ************************/
+
+/***************************** Global variables *********************/
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+static struct real_driver a2232_real_driver = {
+        a2232_disable_tx_interrupts,
+        a2232_enable_tx_interrupts,
+        a2232_disable_rx_interrupts,
+        a2232_enable_rx_interrupts,
+        a2232_shutdown_port,
+        a2232_set_real_termios,
+        a2232_chars_in_buffer,
+        a2232_close,
+        a2232_hungup,
+	NULL	/* a2232_getserial */
+};
+
+static void *a2232_driver_ID = &a2232_driver_ID; // Some memory address WE own.
+
+/* Ports structs */
+static struct a2232_port a2232_ports[MAX_A2232_BOARDS*NUMLINES];
+
+/* TTY driver structs */
+static struct tty_driver *a2232_driver;
+
+/* nr of cards completely (all ports) and correctly configured */
+static int nr_a2232; 
+
+/* zorro_dev structs for the A2232's */
+static struct zorro_dev *zd_a2232[MAX_A2232_BOARDS]; 
+/***************************** End of Global variables **************/
+
+/* Helper functions */
+
+static inline volatile struct a2232memory *a2232mem(unsigned int board)
+{
+	return (volatile struct a2232memory *)ZTWO_VADDR(zd_a2232[board]->resource.start);
+}
+
+static inline volatile struct a2232status *a2232stat(unsigned int board,
+						     unsigned int portonboard)
+{
+	volatile struct a2232memory *mem = a2232mem(board);
+	return &(mem->Status[portonboard]);
+}
+
+static inline void a2232_receive_char(struct a2232_port *port, int ch, int err)
+{
+/* 	Mostly stolen from other drivers.
+	Maybe one could implement a more efficient version by not only
+	transferring one character at a time.
+*/
+	struct tty_struct *tty = port->gs.port.tty;
+
+#if 0
+	switch(err) {
+	case TTY_BREAK:
+		break;
+	case TTY_PARITY:
+		break;
+	case TTY_OVERRUN:
+		break;
+	case TTY_FRAME:
+		break;
+	}
+#endif
+
+	tty_insert_flip_char(tty, ch, err);
+	tty_flip_buffer_push(tty);
+}
+
+/***************************** Functions ****************************/
+/*** BEGIN OF REAL_DRIVER FUNCTIONS ***/
+
+static void a2232_disable_tx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+  
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	stat->OutDisable = -1;
+
+	/* Does this here really have to be? */
+	local_irq_save(flags);
+	port->gs.port.flags &= ~GS_TX_INTEN;
+	local_irq_restore(flags);
+}
+
+static void a2232_enable_tx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	stat->OutDisable = 0;
+
+	/* Does this here really have to be? */
+	local_irq_save(flags);
+	port->gs.port.flags |= GS_TX_INTEN;
+	local_irq_restore(flags);
+}
+
+static void a2232_disable_rx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	port = ptr;
+	port->disable_rx = -1;
+}
+
+static void a2232_enable_rx_interrupts(void *ptr)
+{
+	struct a2232_port *port;
+	port = ptr;
+	port->disable_rx = 0;
+}
+
+static int  a2232_carrier_raised(struct tty_port *port)
+{
+	struct a2232_port *ap = container_of(port, struct a2232_port, gs.port);
+	return ap->cd_status;
+}
+
+static void a2232_shutdown_port(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *stat;
+	unsigned long flags;
+
+	port = ptr;
+	stat = a2232stat(port->which_a2232, port->which_port_on_a2232);
+
+	local_irq_save(flags);
+
+	port->gs.port.flags &= ~GS_ACTIVE;
+	
+	if (port->gs.port.tty && port->gs.port.tty->termios->c_cflag & HUPCL) {
+		/* Set DTR and RTS to Low, flush output.
+		   The NetBSD driver "msc.c" does it this way. */
+		stat->Command = (	(stat->Command & ~A2232CMD_CMask) | 
+					A2232CMD_Close );
+		stat->OutFlush = -1;
+		stat->Setup = -1;
+	}
+
+	local_irq_restore(flags);
+	
+	/* After analyzing control flow, I think a2232_shutdown_port
+		is actually the last call from the system when at application
+		level someone issues a "echo Hello >>/dev/ttyY0".
+		Therefore I think the MOD_DEC_USE_COUNT should be here and
+		not in "a2232_close()". See the comment in "sx.c", too.
+		If you run into problems, compile this driver into the
+		kernel instead of compiling it as a module. */
+}
+
+static int  a2232_set_real_termios(void *ptr)
+{
+	unsigned int cflag, baud, chsize, stopb, parity, softflow;
+	int rate;
+	int a2232_param, a2232_cmd;
+	unsigned long flags;
+	unsigned int i;
+	struct a2232_port *port = ptr;
+	volatile struct a2232status *status;
+	volatile struct a2232memory *mem;
+
+	if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0;
+
+	status = a2232stat(port->which_a2232, port->which_port_on_a2232);
+	mem = a2232mem(port->which_a2232);
+	
+	a2232_param = a2232_cmd = 0;
+
+	// get baud rate
+	baud = port->gs.baud;
+	if (baud == 0) {
+		/* speed == 0 -> drop DTR, do nothing else */
+		local_irq_save(flags);
+		// Clear DTR (and RTS... mhhh).
+		status->Command = (	(status->Command & ~A2232CMD_CMask) |
+					A2232CMD_Close );
+		status->OutFlush = -1;
+		status->Setup = -1;
+		
+		local_irq_restore(flags);
+		return 0;
+	}
+	
+	rate = A2232_BAUD_TABLE_NOAVAIL;
+	for (i=0; i < A2232_BAUD_TABLE_NUM_RATES * 3; i += 3){
+		if (a2232_baud_table[i] == baud){
+			if (mem->Common.Crystal == A2232_TURBO) rate = a2232_baud_table[i+2];
+			else                                    rate = a2232_baud_table[i+1];
+		}
+	}
+	if (rate == A2232_BAUD_TABLE_NOAVAIL){
+		printk("a2232: Board %d Port %d unsupported baud rate: %d baud. Using another.\n",port->which_a2232,port->which_port_on_a2232,baud);
+		// This is useful for both (turbo or normal) Crystal versions.
+		rate = A2232PARAM_B9600;
+	}
+	a2232_param |= rate;
+
+	cflag  = port->gs.port.tty->termios->c_cflag;
+
+	// get character size
+	chsize = cflag & CSIZE;
+	switch (chsize){
+		case CS8: 	a2232_param |= A2232PARAM_8Bit; break;
+		case CS7: 	a2232_param |= A2232PARAM_7Bit; break;
+		case CS6: 	a2232_param |= A2232PARAM_6Bit; break;
+		case CS5: 	a2232_param |= A2232PARAM_5Bit; break;
+		default:	printk("a2232: Board %d Port %d unsupported character size: %d. Using 8 data bits.\n",
+					port->which_a2232,port->which_port_on_a2232,chsize);
+				a2232_param |= A2232PARAM_8Bit; break;
+	}
+
+	// get number of stop bits
+	stopb  = cflag & CSTOPB;
+	if (stopb){ // two stop bits instead of one
+		printk("a2232: Board %d Port %d 2 stop bits unsupported. Using 1 stop bit.\n",
+			port->which_a2232,port->which_port_on_a2232);
+	}
+
+	// Warn if RTS/CTS not wanted
+	if (!(cflag & CRTSCTS)){
+#ifndef A2232_SUPPRESS_RTSCTS_WARNING
+		printk("a2232: Board %d Port %d cannot switch off firmware-implemented RTS/CTS hardware flow control.\n",
+			port->which_a2232,port->which_port_on_a2232);
+#endif
+	}
+
+	/*	I think this is correct.
+		However, IXOFF means _input_ flow control and I wonder
+		if one should care about IXON _output_ flow control,
+		too. If this makes problems, one should turn the A2232
+		firmware XON/XOFF "SoftFlow" flow control off and use
+		the conventional way of inserting START/STOP characters
+		by hand in throttle()/unthrottle().
+	*/
+	softflow = !!( port->gs.port.tty->termios->c_iflag & IXOFF );
+
+	// get Parity (Enabled/Disabled? If Enabled, Odd or Even?)
+	parity = cflag & (PARENB | PARODD);
+	if (parity & PARENB){
+		if (parity & PARODD){
+			a2232_cmd |= A2232CMD_OddParity;
+		}
+		else{
+			a2232_cmd |= A2232CMD_EvenParity;
+		}
+	}
+	else a2232_cmd |= A2232CMD_NoParity;
+
+
+	/*	Hmm. Maybe an own a2232_port structure
+		member would be cleaner?	*/
+	if (cflag & CLOCAL)
+		port->gs.port.flags &= ~ASYNC_CHECK_CD;
+	else
+		port->gs.port.flags |= ASYNC_CHECK_CD;
+
+
+	/* Now we have all parameters and can go to set them: */
+	local_irq_save(flags);
+
+	status->Param = a2232_param | A2232PARAM_RcvBaud;
+	status->Command = a2232_cmd | A2232CMD_Open |  A2232CMD_Enable;
+	status->SoftFlow = softflow;
+	status->OutDisable = 0;
+	status->Setup = -1;
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+static int  a2232_chars_in_buffer(void *ptr)
+{
+	struct a2232_port *port;
+	volatile struct a2232status *status; 
+	unsigned char ret; /* we need modulo-256 arithmetics */
+	port = ptr;
+	status = a2232stat(port->which_a2232, port->which_port_on_a2232);
+#if A2232_IOBUFLEN != 256
+#error "Re-Implement a2232_chars_in_buffer()!"
+#endif
+	ret = (status->OutHead - status->OutTail);
+	return ret;
+}
+
+static void a2232_close(void *ptr)
+{
+	a2232_disable_tx_interrupts(ptr);
+	a2232_disable_rx_interrupts(ptr);
+	/* see the comment in a2232_shutdown_port above. */
+}
+
+static void a2232_hungup(void *ptr)
+{
+	a2232_close(ptr);
+}
+/*** END   OF REAL_DRIVER FUNCTIONS ***/
+
+/*** BEGIN  FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
+static int a2232_ioctl(	struct tty_struct *tty,
+			unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+static void a2232_throttle(struct tty_struct *tty)
+{
+/* Throttle: System cannot take another chars: Drop RTS or
+             send the STOP char or whatever.
+   The A2232 firmware does RTS/CTS anyway, and XON/XOFF
+   if switched on. So the only thing we can do at this
+   layer here is not taking any characters out of the
+   A2232 buffer any more. */
+	struct a2232_port *port = tty->driver_data;
+	port->throttle_input = -1;
+}
+
+static void a2232_unthrottle(struct tty_struct *tty)
+{
+/* Unthrottle: dual to "throttle()" above. */
+	struct a2232_port *port = tty->driver_data;
+	port->throttle_input = 0;
+}
+
+static int  a2232_open(struct tty_struct * tty, struct file * filp)
+{
+/* More or less stolen from other drivers. */
+	int line;
+	int retval;
+	struct a2232_port *port;
+
+	line = tty->index;
+	port = &a2232_ports[line];
+	
+	tty->driver_data = port;
+	port->gs.port.tty = tty;
+	port->gs.port.count++;
+	retval = gs_init_port(&port->gs);
+	if (retval) {
+		port->gs.port.count--;
+		return retval;
+	}
+	port->gs.port.flags |= GS_ACTIVE;
+	retval = gs_block_til_ready(port, filp);
+
+	if (retval) {
+		port->gs.port.count--;
+		return retval;
+	}
+
+	a2232_enable_rx_interrupts(port);
+	
+	return 0;
+}
+/*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
+
+static irqreturn_t a2232_vbl_inter(int irq, void *data)
+{
+#if A2232_IOBUFLEN != 256
+#error "Re-Implement a2232_vbl_inter()!"
+#endif
+
+struct a2232_port *port;
+volatile struct a2232memory *mem;
+volatile struct a2232status *status;
+unsigned char newhead;
+unsigned char bufpos; /* Must be unsigned char. We need the modulo-256 arithmetics */
+unsigned char ncd, ocd, ccd; /* names consistent with the NetBSD driver */
+volatile u_char *ibuf, *cbuf, *obuf;
+int ch, err, n, p;
+	for (n = 0; n < nr_a2232; n++){		/* for every completely initialized A2232 board */
+		mem = a2232mem(n);
+		for (p = 0; p < NUMLINES; p++){	/* for every port on this board */
+			err = 0;
+			port = &a2232_ports[n*NUMLINES+p];
+			if ( port->gs.port.flags & GS_ACTIVE ){ /* if the port is used */
+
+				status = a2232stat(n,p);
+
+				if (!port->disable_rx && !port->throttle_input){ /* If input is not disabled */
+					newhead = status->InHead;               /* 65EC02 write pointer */
+					bufpos = status->InTail;
+
+					/* check for input for this port */
+					if (newhead != bufpos) {
+						/* buffer for input chars/events */
+						ibuf = mem->InBuf[p];
+ 
+						/* data types of bytes in ibuf */
+						cbuf = mem->InCtl[p];
+ 
+						/* do for all chars */
+						while (bufpos != newhead) {
+							/* which type of input data? */
+							switch (cbuf[bufpos]) {
+								/* switch on input event (CD, BREAK, etc.) */
+							case A2232INCTL_EVENT:
+								switch (ibuf[bufpos++]) {
+								case A2232EVENT_Break:
+									/* TODO: Handle BREAK signal */
+									break;
+									/*	A2232EVENT_CarrierOn and A2232EVENT_CarrierOff are
+										handled in a separate queue and should not occur here. */
+								case A2232EVENT_Sync:
+									printk("A2232: 65EC02 software sent SYNC event, don't know what to do. Ignoring.");
+									break;
+								default:
+									printk("A2232: 65EC02 software broken, unknown event type %d occurred.\n",ibuf[bufpos-1]);
+								} /* event type switch */
+								break;
+ 							case A2232INCTL_CHAR:
+								/* Receive incoming char */
+								a2232_receive_char(port, ibuf[bufpos], err);
+								bufpos++;
+								break;
+ 							default:
+								printk("A2232: 65EC02 software broken, unknown data type %d occurred.\n",cbuf[bufpos]);
+								bufpos++;
+							} /* switch on input data type */
+						} /* while there's something in the buffer */
+
+						status->InTail = bufpos;            /* tell 65EC02 what we've read */
+						
+					} /* if there was something in the buffer */                          
+				} /* If input is not disabled */
+
+				/* Now check if there's something to output */
+				obuf = mem->OutBuf[p];
+				bufpos = status->OutHead;
+				while ( (port->gs.xmit_cnt > 0)		&&
+					(!port->gs.port.tty->stopped)	&&
+					(!port->gs.port.tty->hw_stopped) ){	/* While there are chars to transmit */
+					if (((bufpos+1) & A2232_IOBUFLENMASK) != status->OutTail) { /* If the A2232 buffer is not full */
+						ch = port->gs.xmit_buf[port->gs.xmit_tail];					/* get the next char to transmit */
+						port->gs.xmit_tail = (port->gs.xmit_tail+1) & (SERIAL_XMIT_SIZE-1); /* modulo-addition for the gs.xmit_buf ring-buffer */
+						obuf[bufpos++] = ch;																/* put it into the A2232 buffer */
+						port->gs.xmit_cnt--;
+					}
+					else{																									/* If A2232 the buffer is full */
+						break;																							/* simply stop filling it. */
+					}													
+				}					
+				status->OutHead = bufpos;
+					
+				/* WakeUp if output buffer runs low */
+				if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) {
+					tty_wakeup(port->gs.port.tty);
+				}
+			} // if the port is used
+		} // for every port on the board
+			
+		/* Now check the CD message queue */
+		newhead = mem->Common.CDHead;
+		bufpos = mem->Common.CDTail;
+		if (newhead != bufpos){				/* There are CD events in queue */
+			ocd = mem->Common.CDStatus; 		/* get old status bits */
+			while (newhead != bufpos){		/* read all events */
+				ncd = mem->CDBuf[bufpos++]; 	/* get one event */
+				ccd = ncd ^ ocd; 		/* mask of changed lines */
+				ocd = ncd; 			/* save new status bits */
+				for(p=0; p < NUMLINES; p++){	/* for all ports */
+					if (ccd & 1){		/* this one changed */
+
+						struct a2232_port *port = &a2232_ports[n*7+p];
+						port->cd_status = !(ncd & 1); /* ncd&1 <=> CD is now off */
+
+						if (!(port->gs.port.flags & ASYNC_CHECK_CD))
+							;	/* Don't report DCD changes */
+						else if (port->cd_status) { // if DCD on: DCD went UP!
+							
+							/* Are we blocking in open?*/
+							wake_up_interruptible(&port->gs.port.open_wait);
+						}
+						else { // if DCD off: DCD went DOWN!
+							if (port->gs.port.tty)
+								tty_hangup (port->gs.port.tty);
+						}
+						
+					} // if CD changed for this port
+					ccd >>= 1;
+					ncd >>= 1;									/* Shift bits for next line */
+				} // for every port
+			} // while CD events in queue
+			mem->Common.CDStatus = ocd; /* save new status */
+			mem->Common.CDTail = bufpos; /* remove events */
+		} // if events in CD queue
+		
+	} // for every completely initialized A2232 board
+	return IRQ_HANDLED;
+}
+
+static const struct tty_port_operations a2232_port_ops = {
+	.carrier_raised = a2232_carrier_raised,
+};
+
+static void a2232_init_portstructs(void)
+{
+	struct a2232_port *port;
+	int i;
+
+	for (i = 0; i < MAX_A2232_BOARDS*NUMLINES; i++) {
+		port = a2232_ports + i;
+		tty_port_init(&port->gs.port);
+		port->gs.port.ops = &a2232_port_ops;
+		port->which_a2232 = i/NUMLINES;
+		port->which_port_on_a2232 = i%NUMLINES;
+		port->disable_rx = port->throttle_input = port->cd_status = 0;
+		port->gs.magic = A2232_MAGIC;
+		port->gs.close_delay = HZ/2;
+		port->gs.closing_wait = 30 * HZ;
+		port->gs.rd = &a2232_real_driver;
+	}
+}
+
+static const struct tty_operations a2232_ops = {
+	.open = a2232_open,
+	.close = gs_close,
+	.write = gs_write,
+	.put_char = gs_put_char,
+	.flush_chars = gs_flush_chars,
+	.write_room = gs_write_room,
+	.chars_in_buffer = gs_chars_in_buffer,
+	.flush_buffer = gs_flush_buffer,
+	.ioctl = a2232_ioctl,
+	.throttle = a2232_throttle,
+	.unthrottle = a2232_unthrottle,
+	.set_termios = gs_set_termios,
+	.stop = gs_stop,
+	.start = gs_start,
+	.hangup = gs_hangup,
+};
+
+static int a2232_init_drivers(void)
+{
+	int error;
+
+	a2232_driver = alloc_tty_driver(NUMLINES * nr_a2232);
+	if (!a2232_driver)
+		return -ENOMEM;
+	a2232_driver->owner = THIS_MODULE;
+	a2232_driver->driver_name = "commodore_a2232";
+	a2232_driver->name = "ttyY";
+	a2232_driver->major = A2232_NORMAL_MAJOR;
+	a2232_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	a2232_driver->subtype = SERIAL_TYPE_NORMAL;
+	a2232_driver->init_termios = tty_std_termios;
+	a2232_driver->init_termios.c_cflag =
+		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	a2232_driver->init_termios.c_ispeed = 9600;
+	a2232_driver->init_termios.c_ospeed = 9600;
+	a2232_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(a2232_driver, &a2232_ops);
+	if ((error = tty_register_driver(a2232_driver))) {
+		printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n",
+		       error);
+		put_tty_driver(a2232_driver);
+		return 1;
+	}
+	return 0;
+}
+
+static int __init a2232board_init(void)
+{
+	struct zorro_dev *z;
+
+	unsigned int boardaddr;
+	int bcount;
+	short start;
+	u_char *from;
+	volatile u_char *to;
+	volatile struct a2232memory *mem;
+	int error, i;
+
+#ifdef CONFIG_SMP
+	return -ENODEV;	/* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */
+#endif
+
+	if (!MACH_IS_AMIGA){
+		return -ENODEV;
+	}
+
+	printk("Commodore A2232 driver initializing.\n"); /* Say that we're alive. */
+
+	z = NULL;
+	nr_a2232 = 0;
+	while ( (z = zorro_find_device(ZORRO_WILDCARD, z)) ){
+		if (	(z->id != ZORRO_PROD_CBM_A2232_PROTOTYPE) && 
+			(z->id != ZORRO_PROD_CBM_A2232)	){
+			continue;	// The board found was no A2232
+		}
+		if (!zorro_request_device(z,"A2232 driver"))
+			continue;
+
+		printk("Commodore A2232 found (#%d).\n",nr_a2232);
+
+		zd_a2232[nr_a2232] = z;
+
+		boardaddr = ZTWO_VADDR( z->resource.start );
+		printk("Board is located at address 0x%x, size is 0x%x.\n", boardaddr, (unsigned int) ((z->resource.end+1) - (z->resource.start)));
+
+		mem = (volatile struct a2232memory *) boardaddr;
+
+		(void) mem->Enable6502Reset;   /* copy the code across to the board */
+		to = (u_char *)mem;  from = a2232_65EC02code; bcount = sizeof(a2232_65EC02code) - 2;
+		start = *(short *)from;
+		from += sizeof(start);
+		to += start;
+		while(bcount--) *to++ = *from++;
+		printk("65EC02 software uploaded to the A2232 memory.\n");
+  
+		mem->Common.Crystal = A2232_UNKNOWN;  /* use automatic speed check */
+  
+		/* start 6502 running */
+		(void) mem->ResetBoard;
+		printk("A2232's 65EC02 CPU up and running.\n");
+  
+		/* wait until speed detector has finished */
+		for (bcount = 0; bcount < 2000; bcount++) {
+			udelay(1000);
+			if (mem->Common.Crystal)
+				break;
+		}
+		printk((mem->Common.Crystal?"A2232 oscillator crystal detected by 65EC02 software: ":"65EC02 software could not determine A2232 oscillator crystal: "));
+		switch (mem->Common.Crystal){
+		case A2232_UNKNOWN:
+			printk("Unknown crystal.\n");
+			break;
+ 		case A2232_NORMAL:
+			printk ("Normal crystal.\n");
+			break;
+		case A2232_TURBO:
+			printk ("Turbo crystal.\n");
+			break;
+		default:
+			printk ("0x%x. Huh?\n",mem->Common.Crystal);
+		}
+
+		nr_a2232++;
+
+	}	
+
+	printk("Total: %d A2232 boards initialized.\n", nr_a2232); /* Some status report if no card was found */
+
+	a2232_init_portstructs();
+
+	/*
+		a2232_init_drivers also registers the drivers. Must be here because all boards
+		have to be detected first.
+	*/
+	if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx?
+
+	error = request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0,
+			    "A2232 serial VBL", a2232_driver_ID);
+	if (error) {
+		for (i = 0; i < nr_a2232; i++)
+			zorro_release_device(zd_a2232[i]);
+		tty_unregister_driver(a2232_driver);
+		put_tty_driver(a2232_driver);
+	}
+	return error;
+}
+
+static void __exit a2232board_exit(void)
+{
+	int i;
+
+	for (i = 0; i < nr_a2232; i++) {
+		zorro_release_device(zd_a2232[i]);
+	}
+
+	tty_unregister_driver(a2232_driver);
+	put_tty_driver(a2232_driver);
+	free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID);
+}
+
+module_init(a2232board_init);
+module_exit(a2232board_exit);
+
+MODULE_AUTHOR("Enver Haase");
+MODULE_DESCRIPTION("Amiga A2232 multi-serial board driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/generic_serial/ser_a2232.h b/drivers/staging/generic_serial/ser_a2232.h
new file mode 100644
index 0000000..bc09eb9
--- /dev/null
+++ b/drivers/staging/generic_serial/ser_a2232.h
@@ -0,0 +1,202 @@
+/* drivers/char/ser_a2232.h */
+
+/* $Id: ser_a2232.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/* Linux serial driver for the Amiga A2232 board */
+
+/* This driver is MAINTAINED. Before applying any changes, please contact
+ * the author.
+ */
+   
+/* Copyright (c) 2000-2001 Enver Haase    <ehaase@inf.fu-berlin.de>
+ *                   alias The A2232 driver project <A2232@gmx.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.
+ *  
+ */
+
+#ifndef _SER_A2232_H_
+#define _SER_A2232_H_
+
+/*
+	How many boards are to be supported at maximum;
+	"up to five A2232 Multiport Serial Cards may be installed in a
+	single Amiga 2000" states the A2232 User's Guide. If you have
+	more slots available, you might want to change the value below.
+*/
+#define MAX_A2232_BOARDS 5
+
+#ifndef A2232_NORMAL_MAJOR
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define A2232_NORMAL_MAJOR  224	/* /dev/ttyY* */
+#define A2232_CALLOUT_MAJOR 225	/* /dev/cuy*  */
+#endif
+
+/* Some magic is always good - Who knows :) */
+#define A2232_MAGIC 0x000a2232
+
+/* A2232 port structure to keep track of the
+   status of every single line used */
+struct a2232_port{
+	struct gs_port gs;
+	unsigned int which_a2232;
+	unsigned int which_port_on_a2232;
+	short disable_rx;
+	short throttle_input;
+	short cd_status;
+};
+
+#define	NUMLINES		7	/* number of lines per board */
+#define	A2232_IOBUFLEN		256	/* number of bytes per buffer */
+#define	A2232_IOBUFLENMASK	0xff	/* mask for maximum number of bytes */
+
+
+#define	A2232_UNKNOWN	0	/* crystal not known */
+#define	A2232_NORMAL	1	/* normal A2232 (1.8432 MHz oscillator) */
+#define	A2232_TURBO	2	/* turbo A2232 (3.6864 MHz oscillator) */
+
+
+struct a2232common {
+	char   Crystal;	/* normal (1) or turbo (2) board? */
+	u_char Pad_a;
+	u_char TimerH;	/* timer value after speed check */
+	u_char TimerL;
+	u_char CDHead;	/* head pointer for CD message queue */
+	u_char CDTail;	/* tail pointer for CD message queue */
+	u_char CDStatus;
+	u_char Pad_b;
+};
+
+struct a2232status {
+	u_char InHead;		/* input queue head */
+	u_char InTail;		/* input queue tail */
+	u_char OutDisable;	/* disables output */
+	u_char OutHead;		/* output queue head */
+	u_char OutTail;		/* output queue tail */
+	u_char OutCtrl;		/* soft flow control character to send */
+	u_char OutFlush;	/* flushes output buffer */
+	u_char Setup;		/* causes reconfiguration */
+	u_char Param;		/* parameter byte - see A2232PARAM */
+	u_char Command;		/* command byte - see A2232CMD */
+	u_char SoftFlow;	/* enables xon/xoff flow control */
+	/* private 65EC02 fields: */
+	u_char XonOff;		/* stores XON/XOFF enable/disable */
+};
+
+#define	A2232_MEMPAD1	\
+	(0x0200 - NUMLINES * sizeof(struct a2232status)	-	\
+	sizeof(struct a2232common))
+#define	A2232_MEMPAD2	(0x2000 - NUMLINES * A2232_IOBUFLEN - A2232_IOBUFLEN)
+
+struct a2232memory {
+	struct a2232status Status[NUMLINES];	/* 0x0000-0x006f status areas */
+	struct a2232common Common;		/* 0x0070-0x0077 common flags */
+	u_char Dummy1[A2232_MEMPAD1];		/* 0x00XX-0x01ff */
+	u_char OutBuf[NUMLINES][A2232_IOBUFLEN];/* 0x0200-0x08ff output bufs */
+	u_char InBuf[NUMLINES][A2232_IOBUFLEN];	/* 0x0900-0x0fff input bufs */
+	u_char InCtl[NUMLINES][A2232_IOBUFLEN];	/* 0x1000-0x16ff control data */
+	u_char CDBuf[A2232_IOBUFLEN];		/* 0x1700-0x17ff CD event buffer */
+	u_char Dummy2[A2232_MEMPAD2];		/* 0x1800-0x2fff */
+	u_char Code[0x1000];			/* 0x3000-0x3fff code area */
+	u_short InterruptAck;			/* 0x4000        intr ack */
+	u_char Dummy3[0x3ffe];			/* 0x4002-0x7fff */
+	u_short Enable6502Reset;		/* 0x8000 Stop board, */
+						/*  6502 RESET line held low */
+	u_char Dummy4[0x3ffe];			/* 0x8002-0xbfff */
+	u_short ResetBoard;			/* 0xc000 reset board & run, */
+						/*  6502 RESET line held high */
+};
+
+#undef A2232_MEMPAD1
+#undef A2232_MEMPAD2
+
+#define	A2232INCTL_CHAR		0	/* corresponding byte in InBuf is a character */
+#define	A2232INCTL_EVENT	1	/* corresponding byte in InBuf is an event */
+
+#define	A2232EVENT_Break	1	/* break set */
+#define	A2232EVENT_CarrierOn	2	/* carrier raised */
+#define	A2232EVENT_CarrierOff	3	/* carrier dropped */
+#define A2232EVENT_Sync		4	/* don't know, defined in 2232.ax */
+
+#define	A2232CMD_Enable		0x1	/* enable/DTR bit */
+#define	A2232CMD_Close		0x2	/* close the device */
+#define	A2232CMD_Open		0xb	/* open the device */
+#define	A2232CMD_CMask		0xf	/* command mask */
+#define	A2232CMD_RTSOff		0x0  	/* turn off RTS */
+#define	A2232CMD_RTSOn		0x8	/* turn on RTS */
+#define	A2232CMD_Break		0xd	/* transmit a break */
+#define	A2232CMD_RTSMask	0xc	/* mask for RTS stuff */
+#define	A2232CMD_NoParity	0x00	/* don't use parity */
+#define	A2232CMD_OddParity	0x20	/* odd parity */
+#define	A2232CMD_EvenParity	0x60	/* even parity */
+#define	A2232CMD_ParityMask	0xe0	/* parity mask */
+
+#define	A2232PARAM_B115200	0x0	/* baud rates */
+#define	A2232PARAM_B50		0x1
+#define	A2232PARAM_B75		0x2
+#define	A2232PARAM_B110		0x3
+#define	A2232PARAM_B134		0x4
+#define	A2232PARAM_B150		0x5
+#define	A2232PARAM_B300		0x6
+#define	A2232PARAM_B600		0x7
+#define	A2232PARAM_B1200	0x8
+#define	A2232PARAM_B1800	0x9
+#define	A2232PARAM_B2400	0xa
+#define	A2232PARAM_B3600	0xb
+#define	A2232PARAM_B4800	0xc
+#define	A2232PARAM_B7200	0xd
+#define	A2232PARAM_B9600	0xe
+#define	A2232PARAM_B19200	0xf
+#define	A2232PARAM_BaudMask	0xf	/* baud rate mask */
+#define	A2232PARAM_RcvBaud	0x10	/* enable receive baud rate */
+#define	A2232PARAM_8Bit		0x00	/* numbers of bits */
+#define	A2232PARAM_7Bit		0x20
+#define	A2232PARAM_6Bit		0x40
+#define	A2232PARAM_5Bit		0x60
+#define	A2232PARAM_BitMask	0x60	/* numbers of bits mask */
+
+
+/* Standard speeds tables, -1 means unavailable, -2 means 0 baud: switch off line */
+#define A2232_BAUD_TABLE_NOAVAIL -1
+#define A2232_BAUD_TABLE_NUM_RATES (18)
+static int a2232_baud_table[A2232_BAUD_TABLE_NUM_RATES*3] = {
+	//Baud	//Normal			//Turbo
+	50,	A2232PARAM_B50,			A2232_BAUD_TABLE_NOAVAIL,
+	75,	A2232PARAM_B75,			A2232_BAUD_TABLE_NOAVAIL,
+	110,	A2232PARAM_B110,		A2232_BAUD_TABLE_NOAVAIL,
+	134,	A2232PARAM_B134,		A2232_BAUD_TABLE_NOAVAIL,
+	150,	A2232PARAM_B150,		A2232PARAM_B75,
+	200,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+	300,	A2232PARAM_B300,		A2232PARAM_B150,
+	600,	A2232PARAM_B600,		A2232PARAM_B300,
+	1200,	A2232PARAM_B1200,		A2232PARAM_B600,
+	1800,	A2232PARAM_B1800,		A2232_BAUD_TABLE_NOAVAIL,
+	2400,	A2232PARAM_B2400,		A2232PARAM_B1200,
+	4800,	A2232PARAM_B4800,		A2232PARAM_B2400,
+	9600,	A2232PARAM_B9600,		A2232PARAM_B4800,
+	19200,	A2232PARAM_B19200,		A2232PARAM_B9600,
+	38400,	A2232_BAUD_TABLE_NOAVAIL,	A2232PARAM_B19200,
+	57600,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+#ifdef A2232_SPEEDHACK
+	115200,	A2232PARAM_B115200,		A2232_BAUD_TABLE_NOAVAIL,
+	230400,	A2232_BAUD_TABLE_NOAVAIL,	A2232PARAM_B115200
+#else
+	115200,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL,
+	230400,	A2232_BAUD_TABLE_NOAVAIL,	A2232_BAUD_TABLE_NOAVAIL
+#endif
+};
+#endif
diff --git a/drivers/staging/generic_serial/ser_a2232fw.ax b/drivers/staging/generic_serial/ser_a2232fw.ax
new file mode 100644
index 0000000..7364380
--- /dev/null
+++ b/drivers/staging/generic_serial/ser_a2232fw.ax
@@ -0,0 +1,529 @@
+;.lib "axm"
+;
+;begin
+;title "A2232 serial board driver"
+;
+;set modules "2232"
+;set executable "2232.bin"
+;
+;;;;set nolink
+;
+;set temporary directory "t:"
+;
+;set assembly options "-m6502 -l60:t:list"
+;set link options "bin"; loadadr"
+;;;bin2c 2232.bin msc6502.h msc6502code
+;end
+;
+;
+; ### Commodore A2232 serial board driver for NetBSD by JM v1.3 ###
+;
+; - Created 950501 by JM -
+;
+;
+; Serial board driver software.
+;
+;
+% Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
+% All rights reserved.
+%
+% Redistribution and use in source and binary forms, with or without
+% modification, are permitted provided that the following conditions
+% are met:
+% 1. Redistributions of source code must retain the above copyright
+%    notice, and the entire permission notice in its entirety,
+%    including the disclaimer of warranties.
+% 2. Redistributions in binary form must reproduce the above copyright
+%    notice, this list of conditions and the following disclaimer in the
+%    documentation and/or other materials provided with the distribution.
+% 3. The name of the author may not be used to endorse or promote
+%    products derived from this software without specific prior
+%    written permission.
+%
+% ALTERNATIVELY, this product may be distributed under the terms of
+% the GNU General Public License, in which case the provisions of the
+% GPL are required INSTEAD OF the above restrictions.  (This clause is
+% necessary due to a potential bad interaction between the GPL and
+% the restrictions contained in a BSD-style copyright.)
+%
+% THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+% WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+% OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+% DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+% INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+% (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+% SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+% STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+% OF THE POSSIBILITY OF SUCH DAMAGE.
+;
+;
+; Bugs:
+;
+; - Can't send a break yet
+;
+;
+;
+; Edited:
+;
+; - 950501 by JM -> v0.1	- Created this file.
+; - 951029 by JM -> v1.3	- Carrier Detect events now queued in a separate
+;				  queue.
+;
+;
+
+
+CODE		equ	$3800		; start address for program code
+
+
+CTL_CHAR	equ	$00		; byte in ibuf is a character
+CTL_EVENT	equ	$01		; byte in ibuf is an event
+
+EVENT_BREAK	equ	$01
+EVENT_CDON	equ	$02
+EVENT_CDOFF	equ	$03
+EVENT_SYNC	equ	$04
+
+XON		equ	$11
+XOFF		equ	$13
+
+
+VARBASE		macro	*starting_address	; was VARINIT
+_varbase	set	\1
+		endm
+
+VARDEF		macro	*name space_needs
+\1		equ	_varbase
+_varbase	set	_varbase+\2
+		endm
+
+
+stz		macro	* address
+		 db	$64,\1
+		endm
+
+stzax		macro	* address
+		 db	$9e,<\1,>\1
+		endm
+
+
+biti		macro	* immediate value
+		db	$89,\1
+		endm
+
+smb0		macro	* address
+		db	$87,\1
+		endm
+smb1		macro	* address
+		db	$97,\1
+		endm
+smb2		macro	* address
+		db	$a7,\1
+		endm
+smb3		macro	* address
+		db	$b7,\1
+		endm
+smb4		macro	* address
+		db	$c7,\1
+		endm
+smb5		macro	* address
+		db	$d7,\1
+		endm
+smb6		macro	* address
+		db	$e7,\1
+		endm
+smb7		macro	* address
+		db	$f7,\1
+		endm
+
+
+
+;-----------------------------------------------------------------------;
+;									;
+; stuff common for all ports, non-critical (run once / loop)		;
+;									;
+DO_SLOW		macro	* port_number					;
+		.local			;				;
+		lda	CIA+C_PA	; check all CD inputs		;
+		cmp	CommonCDo	; changed from previous accptd?	;
+		beq	=over		; nope, do nothing else here	;
+					;				;
+		cmp	CommonCDb	; bouncing?			;
+		beq	=nobounce	; nope ->			;
+					;				;
+		sta	CommonCDb	; save current state		;
+		lda	#64		; reinitialize counter		;
+		sta	CommonCDc	;				;
+		jmp	=over		; skip CD save			;
+					;				;
+=nobounce	dec	CommonCDc	; no, decrement bounce counter	;
+		bpl	=over		; not done yet, so skip CD save	;
+					;				;
+=saveCD		ldx	CDHead		; get write index		;
+		sta	cdbuf,x		; save status in buffer		;
+		inx			;				;
+		cpx	CDTail		; buffer full?			;
+		.if	ne		; no: preserve status:		;
+		 stx	CDHead		; update index in RAM		;
+		 sta	CommonCDo	; save state for the next check	;
+		.end			;				;
+=over		.end	local						;
+		endm							;
+									;
+;-----------------------------------------------------------------------;
+
+
+; port specific stuff (no data transfer)
+
+DO_PORT		macro	* port_number
+		.local			;				;
+		lda	SetUp\1		; reconfiguration request?	;
+		.if	ne		; yes:				;
+		 lda	SoftFlow\1	; get XON/XOFF flag		;
+		 sta	XonOff\1	; save it			;
+		 lda	Param\1		; get parameter			;
+		 ora	#%00010000	; use baud generator for Rx	;
+		 sta	ACIA\1+A_CTRL	; store in control register	;
+		 stz	OutDisable\1	; enable transmit output	;
+		 stz	SetUp\1		; no reconfiguration no more	;
+		.end			;				;
+					;				;
+		lda	InHead\1	; get write index		;
+		sbc	InTail\1	; buffer full soon?		;
+		cmp	#200		; 200 chars or more in buffer?	;
+		lda	Command\1	; get Command reg value		;
+		and	#%11110011	; turn RTS OFF by default	;
+		.if	cc		; still room in buffer:		;
+		 ora	#%00001000	; turn RTS ON			;
+		.end			;				;
+		sta	ACIA\1+A_CMD	; set/clear RTS			;
+					;				;
+		lda	OutFlush\1	; request to flush output buffer;
+		.if	ne		; yessh!			;
+		 lda	OutHead\1	; get head			;
+		 sta	OutTail\1	; save as tail			;
+		 stz	OutDisable\1	; enable transmit output	;
+		 stz	OutFlush\1	; clear request			;
+		.end
+		.end	local
+		endm
+
+
+DO_DATA		macro	* port number
+		.local
+		lda	ACIA\1+A_SR	; read ACIA status register	;
+		biti	[1<<3]		; something received?		;
+		.if	ne		; yes:				;
+		 biti	[1<<1]		; framing error?		;
+		 .if	ne		; yes:				;
+		  lda	ACIA\1+A_DATA	; read received character	;
+		  bne	=SEND		; not break -> ignore it	;
+		  ldx	InHead\1	; get write pointer		;
+		  lda	#CTL_EVENT	; get type of byte		;
+		  sta	ictl\1,x	; save it in InCtl buffer	;
+		  lda	#EVENT_BREAK	; event code			;
+		  sta	ibuf\1,x	; save it as well		;
+		  inx			;				;
+		  cpx	InTail\1	; still room in buffer?		;
+		  .if	ne		; absolutely:			;
+		   stx	InHead\1	; update index in memory	;
+		  .end			;				;
+		  jmp	=SEND		; go check if anything to send	;
+		 .end			;				;
+		 			; normal char received:		;
+		 ldx	InHead\1	; get write index		;
+		 lda	ACIA\1+A_DATA	; read received character	;
+		 sta	ibuf\1,x	; save char in buffer		;
+		 stzax	ictl\1		; set type to CTL_CHAR		;
+		 inx			;				;
+		 cpx	InTail\1	; buffer full?			;
+		 .if	ne		; no: preserve character:	;
+		  stx	InHead\1	; update index in RAM		;
+		 .end			;				;
+		 and	#$7f		; mask off parity if any	;
+		 cmp	#XOFF		; XOFF from remote host?	;
+		 .if	eq		; yes:				;
+		  lda	XonOff\1	; if XON/XOFF handshaking..	;
+		  sta	OutDisable\1	; ..disable transmitter		;
+		 .end			;				;
+		.end			;				;
+					;				;
+					; BUFFER FULL CHECK WAS HERE	;
+					;				;
+=SEND		lda	ACIA\1+A_SR	; transmit register empty?	;
+		and	#[1<<4]		;				;
+		.if	ne		; yes:				;
+		 ldx	OutCtrl\1	; sending out XON/XOFF?		;
+		 .if	ne		; yes:				;
+		  lda	CIA+C_PB	; check CTS signal		;
+		  and	#[1<<\1]	; (for this port only)		;
+		  bne	=DONE		; not allowed to send -> done	;
+		  stx	ACIA\1+A_DATA	; transmit control char		;
+		  stz	OutCtrl\1	; clear flag			;
+		  jmp	=DONE		; and we're done		;
+		 .end			;				;
+					;				;
+		 ldx	OutTail\1	; anything to transmit?		;
+		 cpx	OutHead\1	;				;
+		 .if	ne		; yes:				;
+		  lda	OutDisable\1	; allowed to transmit?		;
+		  .if	eq		; yes:				;
+		   lda	CIA+C_PB	; check CTS signal		;
+		   and	#[1<<\1]	; (for this port only)		;
+		   bne	=DONE		; not allowed to send -> done	;
+		   lda	obuf\1,x	; get a char from buffer	;
+		   sta	ACIA\1+A_DATA	; send it away			;
+		   inc	OutTail\1	; update read index		;
+		  .end			;				;
+		 .end			;				;
+		.end			;				;
+=DONE		.end	local
+		endm
+
+
+
+PORTVAR		macro	* port number
+		VARDEF	InHead\1 1
+		VARDEF	InTail\1 1
+		VARDEF	OutDisable\1 1
+		VARDEF	OutHead\1 1
+		VARDEF	OutTail\1 1
+		VARDEF	OutCtrl\1 1
+		VARDEF	OutFlush\1 1
+		VARDEF	SetUp\1 1
+		VARDEF	Param\1 1
+		VARDEF	Command\1 1
+		VARDEF	SoftFlow\1 1
+		; private:
+		VARDEF	XonOff\1 1
+		endm
+
+
+ VARBASE 0	; start variables at address $0000
+ PORTVAR 0	; define variables for port 0
+ PORTVAR 1	; define variables for port 1
+ PORTVAR 2	; define variables for port 2
+ PORTVAR 3	; define variables for port 3
+ PORTVAR 4	; define variables for port 4
+ PORTVAR 5	; define variables for port 5
+ PORTVAR 6	; define variables for port 6
+
+
+
+ VARDEF	Crystal	1	; 0 = unknown, 1 = normal, 2 = turbo
+ VARDEF	Pad_a	1
+ VARDEF	TimerH	1
+ VARDEF	TimerL	1
+ VARDEF	CDHead	1
+ VARDEF	CDTail	1
+ VARDEF	CDStatus 1
+ VARDEF	Pad_b	1
+
+ VARDEF	CommonCDo 1	; for carrier detect optimization
+ VARDEF	CommonCDc 1	; for carrier detect debouncing
+ VARDEF	CommonCDb 1	; for carrier detect debouncing
+
+
+ VARBASE $0200
+ VARDEF	obuf0 256	; output data (characters only)
+ VARDEF	obuf1 256
+ VARDEF	obuf2 256
+ VARDEF	obuf3 256
+ VARDEF	obuf4 256
+ VARDEF	obuf5 256
+ VARDEF	obuf6 256
+
+ VARDEF	ibuf0 256	; input data (characters, events etc - see ictl)
+ VARDEF	ibuf1 256
+ VARDEF	ibuf2 256
+ VARDEF	ibuf3 256
+ VARDEF	ibuf4 256
+ VARDEF	ibuf5 256
+ VARDEF	ibuf6 256
+
+ VARDEF	ictl0 256	; input control information (type of data in ibuf)
+ VARDEF	ictl1 256
+ VARDEF	ictl2 256
+ VARDEF	ictl3 256
+ VARDEF	ictl4 256
+ VARDEF	ictl5 256
+ VARDEF	ictl6 256
+
+ VARDEF	cdbuf 256	; CD event queue
+
+
+ACIA0		equ	$4400
+ACIA1		equ	$4c00
+ACIA2		equ	$5400
+ACIA3		equ	$5c00
+ACIA4		equ	$6400
+ACIA5		equ	$6c00
+ACIA6		equ	$7400
+
+A_DATA		equ	$00
+A_SR		equ	$02
+A_CMD		equ	$04
+A_CTRL		equ	$06
+;  00	write transmit data	read received data
+;  02	reset ACIA		read status register
+;  04	write command register	read command register
+;  06	write control register	read control register
+
+CIA		equ	$7c00		; 8520 CIA
+C_PA		equ	$00		; port A data register
+C_PB		equ	$02		; port B data register
+C_DDRA		equ	$04		; data direction register for port A
+C_DDRB		equ	$06		; data direction register for port B
+C_TAL		equ	$08		; timer A
+C_TAH		equ	$0a
+C_TBL		equ	$0c		; timer B
+C_TBH		equ	$0e
+C_TODL		equ	$10		; TOD LSB
+C_TODM		equ	$12		; TOD middle byte
+C_TODH		equ	$14		; TOD MSB
+C_DATA		equ	$18		; serial data register
+C_INTCTRL	equ	$1a		; interrupt control register
+C_CTRLA		equ	$1c		; control register A
+C_CTRLB		equ	$1e		; control register B
+
+
+
+
+
+		section	main,code,CODE-2
+
+		db	>CODE,<CODE
+
+;-----------------------------------------------------------------------;
+; here's the initialization code:					;
+;									;
+R_RESET		ldx	#$ff						;
+		txs			; initialize stack pointer	;
+		cld			; in case a 6502 is used...	;
+		ldx	#0		;				;
+		lda	#0		;				;
+		ldy	#Crystal	; this many bytes to clear	;
+clr_loop	sta	0,x		; clear zero page variables	;
+		inx			;				;
+		dey			;				;
+		bne	clr_loop	;				;
+					;				;
+		stz	CommonCDo	; force CD test at boot		;
+		stz	CommonCDb	;				;
+		stz	CDHead		; clear queue			;
+		stz	CDTail		;				;
+					;				;
+		lda	#0		;				;
+		sta	Pad_a		;				;
+		lda	#170		; test cmp			;
+		cmp	#100		;				;
+		.if	cs		;				;
+		 inc	Pad_a		; C was set			;
+		.end			;				;
+									;
+;-----------------------------------------------------------------------;
+; Speed check								;
+;-----------------------------------------------------------------------;
+									;
+		lda	Crystal		; speed already set?		;
+		beq	DoSpeedy	;				;
+		jmp	LOOP		; yes, skip speed test		;
+					;				;
+DoSpeedy	lda	#%10011000	; 8N1, 1200/2400 bps		;
+		sta	ACIA0+A_CTRL	;				;
+		lda	#%00001011	; enable DTR			;
+		sta	ACIA0+A_CMD	;				;
+		lda	ACIA0+A_SR	; read status register		;
+					;				;
+		lda	#%10000000	; disable all ints (unnecessary);
+		sta	CIA+C_INTCTRL	;				;
+		lda	#255		; program the timer		;
+		sta	CIA+C_TAL	;				;
+		sta	CIA+C_TAH	;				;
+					;				;
+		ldx	#0		;				;
+		stx	ACIA0+A_DATA	; transmit a zero		;
+		nop			;				;
+		nop			;				;
+		lda	ACIA0+A_SR	; read status			;
+		nop			;				;
+		nop			;				;
+		stx	ACIA0+A_DATA	; transmit a zero		;
+Speedy1		lda	ACIA0+A_SR	; read status			;
+		and	#[1<<4]		; transmit data reg empty?	;
+		beq	Speedy1		; not yet, wait more		;
+					;				;
+		lda	#%00010001	; load & start the timer	;
+		stx	ACIA0+A_DATA	; transmit one more zero	;
+		sta	CIA+C_CTRLA	;				;
+Speedy2		lda	ACIA0+A_SR	; read status			;
+		and	#[1<<4]		; transmit data reg empty?	;
+		beq	Speedy2		; not yet, wait more		;
+		stx	CIA+C_CTRLA	; stop the timer		;
+					;				;
+		lda	CIA+C_TAL	; copy timer value for 68k	;
+		sta	TimerL		;				;
+		lda	CIA+C_TAH	;				;
+		sta	TimerH		;				;
+		cmp	#$d0		; turbo or normal?		;
+		.if	cs		;				;
+		 lda	#2		; turbo! :-)			;
+		.else			;				;
+		 lda	#1		; normal :-(			;
+		.end			;				;
+		sta	Crystal		;				;
+		lda	#0		;				;
+		sta	ACIA0+A_SR	;				;
+		sta	ACIA0+A_CTRL	; reset UART			;
+		sta	ACIA0+A_CMD	;				;
+									;
+		jmp	LOOP						;
+									;
+;									;
+;-----------------------------------------------------------------------;
+;									;
+; The Real Thing:							;
+;									;
+LOOP		DO_SLOW			; do non-critical things	;
+		jsr	do_input	; check for received data
+		DO_PORT	0
+		jsr	do_input
+		DO_PORT	1
+		jsr	do_input
+		DO_PORT	2
+		jsr	do_input
+		DO_PORT	3
+		jsr	do_input
+		DO_PORT	4
+		jsr	do_input
+		DO_PORT	5
+		jsr	do_input
+		DO_PORT	6
+		jsr	do_input
+		jmp	LOOP
+
+
+do_input	DO_DATA	0
+		DO_DATA	1
+		DO_DATA	2
+		DO_DATA	3
+		DO_DATA	4
+		DO_DATA	5
+		DO_DATA	6
+		rts
+
+
+;-----------------------------------------------------------------------;
+		section	vectors,data,$3ffa
+		dw	$d0d0
+		dw	R_RESET
+		dw	$c0ce
+;-----------------------------------------------------------------------;
+
+
+
+		end
+
+
+
diff --git a/drivers/staging/generic_serial/ser_a2232fw.h b/drivers/staging/generic_serial/ser_a2232fw.h
new file mode 100644
index 0000000..e09a30a
--- /dev/null
+++ b/drivers/staging/generic_serial/ser_a2232fw.h
@@ -0,0 +1,306 @@
+/* drivers/char/ser_a2232fw.h */
+
+/* $Id: ser_a2232fw.h,v 0.4 2000/01/25 12:00:00 ehaase Exp $ */
+
+/*
+ * Copyright (c) 1995 Jukka Marin <jmarin@jmp.fi>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * ALTERNATIVELY, this product may be distributed under the terms of
+ * the GNU Public License, in which case the provisions of the GPL are
+ * required INSTEAD OF the above restrictions.  (This clause is
+ * necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+                                      
+/* This is the 65EC02 code by Jukka Marin that is executed by
+   the A2232's 65EC02 processor (base address: 0x3800)
+   Source file:	ser_a2232fw.ax
+   Version:	1.3 (951029)
+   Known Bugs:	Cannot send a break yet
+*/
+static unsigned char a2232_65EC02code[] = {
+	0x38, 0x00, 0xA2, 0xFF, 0x9A, 0xD8, 0xA2, 0x00, 
+	0xA9, 0x00, 0xA0, 0x54, 0x95, 0x00, 0xE8, 0x88, 
+	0xD0, 0xFA, 0x64, 0x5C, 0x64, 0x5E, 0x64, 0x58, 
+	0x64, 0x59, 0xA9, 0x00, 0x85, 0x55, 0xA9, 0xAA, 
+	0xC9, 0x64, 0x90, 0x02, 0xE6, 0x55, 0xA5, 0x54, 
+	0xF0, 0x03, 0x4C, 0x92, 0x38, 0xA9, 0x98, 0x8D, 
+	0x06, 0x44, 0xA9, 0x0B, 0x8D, 0x04, 0x44, 0xAD, 
+	0x02, 0x44, 0xA9, 0x80, 0x8D, 0x1A, 0x7C, 0xA9, 
+	0xFF, 0x8D, 0x08, 0x7C, 0x8D, 0x0A, 0x7C, 0xA2, 
+	0x00, 0x8E, 0x00, 0x44, 0xEA, 0xEA, 0xAD, 0x02, 
+	0x44, 0xEA, 0xEA, 0x8E, 0x00, 0x44, 0xAD, 0x02, 
+	0x44, 0x29, 0x10, 0xF0, 0xF9, 0xA9, 0x11, 0x8E, 
+	0x00, 0x44, 0x8D, 0x1C, 0x7C, 0xAD, 0x02, 0x44, 
+	0x29, 0x10, 0xF0, 0xF9, 0x8E, 0x1C, 0x7C, 0xAD, 
+	0x08, 0x7C, 0x85, 0x57, 0xAD, 0x0A, 0x7C, 0x85, 
+	0x56, 0xC9, 0xD0, 0x90, 0x05, 0xA9, 0x02, 0x4C, 
+	0x82, 0x38, 0xA9, 0x01, 0x85, 0x54, 0xA9, 0x00, 
+	0x8D, 0x02, 0x44, 0x8D, 0x06, 0x44, 0x8D, 0x04, 
+	0x44, 0x4C, 0x92, 0x38, 0xAD, 0x00, 0x7C, 0xC5, 
+	0x5C, 0xF0, 0x1F, 0xC5, 0x5E, 0xF0, 0x09, 0x85, 
+	0x5E, 0xA9, 0x40, 0x85, 0x5D, 0x4C, 0xB8, 0x38, 
+	0xC6, 0x5D, 0x10, 0x0E, 0xA6, 0x58, 0x9D, 0x00, 
+	0x17, 0xE8, 0xE4, 0x59, 0xF0, 0x04, 0x86, 0x58, 
+	0x85, 0x5C, 0x20, 0x23, 0x3A, 0xA5, 0x07, 0xF0, 
+	0x0F, 0xA5, 0x0A, 0x85, 0x0B, 0xA5, 0x08, 0x09, 
+	0x10, 0x8D, 0x06, 0x44, 0x64, 0x02, 0x64, 0x07, 
+	0xA5, 0x00, 0xE5, 0x01, 0xC9, 0xC8, 0xA5, 0x09, 
+	0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 
+	0x44, 0xA5, 0x06, 0xF0, 0x08, 0xA5, 0x03, 0x85, 
+	0x04, 0x64, 0x02, 0x64, 0x06, 0x20, 0x23, 0x3A, 
+	0xA5, 0x13, 0xF0, 0x0F, 0xA5, 0x16, 0x85, 0x17, 
+	0xA5, 0x14, 0x09, 0x10, 0x8D, 0x06, 0x4C, 0x64, 
+	0x0E, 0x64, 0x13, 0xA5, 0x0C, 0xE5, 0x0D, 0xC9, 
+	0xC8, 0xA5, 0x15, 0x29, 0xF3, 0xB0, 0x02, 0x09, 
+	0x08, 0x8D, 0x04, 0x4C, 0xA5, 0x12, 0xF0, 0x08, 
+	0xA5, 0x0F, 0x85, 0x10, 0x64, 0x0E, 0x64, 0x12, 
+	0x20, 0x23, 0x3A, 0xA5, 0x1F, 0xF0, 0x0F, 0xA5, 
+	0x22, 0x85, 0x23, 0xA5, 0x20, 0x09, 0x10, 0x8D, 
+	0x06, 0x54, 0x64, 0x1A, 0x64, 0x1F, 0xA5, 0x18, 
+	0xE5, 0x19, 0xC9, 0xC8, 0xA5, 0x21, 0x29, 0xF3, 
+	0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x54, 0xA5, 
+	0x1E, 0xF0, 0x08, 0xA5, 0x1B, 0x85, 0x1C, 0x64, 
+	0x1A, 0x64, 0x1E, 0x20, 0x23, 0x3A, 0xA5, 0x2B, 
+	0xF0, 0x0F, 0xA5, 0x2E, 0x85, 0x2F, 0xA5, 0x2C, 
+	0x09, 0x10, 0x8D, 0x06, 0x5C, 0x64, 0x26, 0x64, 
+	0x2B, 0xA5, 0x24, 0xE5, 0x25, 0xC9, 0xC8, 0xA5, 
+	0x2D, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 
+	0x04, 0x5C, 0xA5, 0x2A, 0xF0, 0x08, 0xA5, 0x27, 
+	0x85, 0x28, 0x64, 0x26, 0x64, 0x2A, 0x20, 0x23, 
+	0x3A, 0xA5, 0x37, 0xF0, 0x0F, 0xA5, 0x3A, 0x85, 
+	0x3B, 0xA5, 0x38, 0x09, 0x10, 0x8D, 0x06, 0x64, 
+	0x64, 0x32, 0x64, 0x37, 0xA5, 0x30, 0xE5, 0x31, 
+	0xC9, 0xC8, 0xA5, 0x39, 0x29, 0xF3, 0xB0, 0x02, 
+	0x09, 0x08, 0x8D, 0x04, 0x64, 0xA5, 0x36, 0xF0, 
+	0x08, 0xA5, 0x33, 0x85, 0x34, 0x64, 0x32, 0x64, 
+	0x36, 0x20, 0x23, 0x3A, 0xA5, 0x43, 0xF0, 0x0F, 
+	0xA5, 0x46, 0x85, 0x47, 0xA5, 0x44, 0x09, 0x10, 
+	0x8D, 0x06, 0x6C, 0x64, 0x3E, 0x64, 0x43, 0xA5, 
+	0x3C, 0xE5, 0x3D, 0xC9, 0xC8, 0xA5, 0x45, 0x29, 
+	0xF3, 0xB0, 0x02, 0x09, 0x08, 0x8D, 0x04, 0x6C, 
+	0xA5, 0x42, 0xF0, 0x08, 0xA5, 0x3F, 0x85, 0x40, 
+	0x64, 0x3E, 0x64, 0x42, 0x20, 0x23, 0x3A, 0xA5, 
+	0x4F, 0xF0, 0x0F, 0xA5, 0x52, 0x85, 0x53, 0xA5, 
+	0x50, 0x09, 0x10, 0x8D, 0x06, 0x74, 0x64, 0x4A, 
+	0x64, 0x4F, 0xA5, 0x48, 0xE5, 0x49, 0xC9, 0xC8, 
+	0xA5, 0x51, 0x29, 0xF3, 0xB0, 0x02, 0x09, 0x08, 
+	0x8D, 0x04, 0x74, 0xA5, 0x4E, 0xF0, 0x08, 0xA5, 
+	0x4B, 0x85, 0x4C, 0x64, 0x4A, 0x64, 0x4E, 0x20, 
+	0x23, 0x3A, 0x4C, 0x92, 0x38, 0xAD, 0x02, 0x44, 
+	0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 
+	0xAD, 0x00, 0x44, 0xD0, 0x32, 0xA6, 0x00, 0xA9, 
+	0x01, 0x9D, 0x00, 0x10, 0xA9, 0x01, 0x9D, 0x00, 
+	0x09, 0xE8, 0xE4, 0x01, 0xF0, 0x02, 0x86, 0x00, 
+	0x4C, 0x65, 0x3A, 0xA6, 0x00, 0xAD, 0x00, 0x44, 
+	0x9D, 0x00, 0x09, 0x9E, 0x00, 0x10, 0xE8, 0xE4, 
+	0x01, 0xF0, 0x02, 0x86, 0x00, 0x29, 0x7F, 0xC9, 
+	0x13, 0xD0, 0x04, 0xA5, 0x0B, 0x85, 0x02, 0xAD, 
+	0x02, 0x44, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x05, 
+	0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, 0xD0, 
+	0x21, 0x8E, 0x00, 0x44, 0x64, 0x05, 0x4C, 0x98, 
+	0x3A, 0xA6, 0x04, 0xE4, 0x03, 0xF0, 0x13, 0xA5, 
+	0x02, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x01, 
+	0xD0, 0x08, 0xBD, 0x00, 0x02, 0x8D, 0x00, 0x44, 
+	0xE6, 0x04, 0xAD, 0x02, 0x4C, 0x89, 0x08, 0xF0, 
+	0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x4C, 
+	0xD0, 0x32, 0xA6, 0x0C, 0xA9, 0x01, 0x9D, 0x00, 
+	0x11, 0xA9, 0x01, 0x9D, 0x00, 0x0A, 0xE8, 0xE4, 
+	0x0D, 0xF0, 0x02, 0x86, 0x0C, 0x4C, 0xDA, 0x3A, 
+	0xA6, 0x0C, 0xAD, 0x00, 0x4C, 0x9D, 0x00, 0x0A, 
+	0x9E, 0x00, 0x11, 0xE8, 0xE4, 0x0D, 0xF0, 0x02, 
+	0x86, 0x0C, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, 
+	0xA5, 0x17, 0x85, 0x0E, 0xAD, 0x02, 0x4C, 0x29, 
+	0x10, 0xF0, 0x2C, 0xA6, 0x11, 0xF0, 0x0F, 0xAD, 
+	0x02, 0x7C, 0x29, 0x02, 0xD0, 0x21, 0x8E, 0x00, 
+	0x4C, 0x64, 0x11, 0x4C, 0x0D, 0x3B, 0xA6, 0x10, 
+	0xE4, 0x0F, 0xF0, 0x13, 0xA5, 0x0E, 0xD0, 0x0F, 
+	0xAD, 0x02, 0x7C, 0x29, 0x02, 0xD0, 0x08, 0xBD, 
+	0x00, 0x03, 0x8D, 0x00, 0x4C, 0xE6, 0x10, 0xAD, 
+	0x02, 0x54, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 
+	0xF0, 0x1B, 0xAD, 0x00, 0x54, 0xD0, 0x32, 0xA6, 
+	0x18, 0xA9, 0x01, 0x9D, 0x00, 0x12, 0xA9, 0x01, 
+	0x9D, 0x00, 0x0B, 0xE8, 0xE4, 0x19, 0xF0, 0x02, 
+	0x86, 0x18, 0x4C, 0x4F, 0x3B, 0xA6, 0x18, 0xAD, 
+	0x00, 0x54, 0x9D, 0x00, 0x0B, 0x9E, 0x00, 0x12, 
+	0xE8, 0xE4, 0x19, 0xF0, 0x02, 0x86, 0x18, 0x29, 
+	0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x23, 0x85, 
+	0x1A, 0xAD, 0x02, 0x54, 0x29, 0x10, 0xF0, 0x2C, 
+	0xA6, 0x1D, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 
+	0x04, 0xD0, 0x21, 0x8E, 0x00, 0x54, 0x64, 0x1D, 
+	0x4C, 0x82, 0x3B, 0xA6, 0x1C, 0xE4, 0x1B, 0xF0, 
+	0x13, 0xA5, 0x1A, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 
+	0x29, 0x04, 0xD0, 0x08, 0xBD, 0x00, 0x04, 0x8D, 
+	0x00, 0x54, 0xE6, 0x1C, 0xAD, 0x02, 0x5C, 0x89, 
+	0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 
+	0x00, 0x5C, 0xD0, 0x32, 0xA6, 0x24, 0xA9, 0x01, 
+	0x9D, 0x00, 0x13, 0xA9, 0x01, 0x9D, 0x00, 0x0C, 
+	0xE8, 0xE4, 0x25, 0xF0, 0x02, 0x86, 0x24, 0x4C, 
+	0xC4, 0x3B, 0xA6, 0x24, 0xAD, 0x00, 0x5C, 0x9D, 
+	0x00, 0x0C, 0x9E, 0x00, 0x13, 0xE8, 0xE4, 0x25, 
+	0xF0, 0x02, 0x86, 0x24, 0x29, 0x7F, 0xC9, 0x13, 
+	0xD0, 0x04, 0xA5, 0x2F, 0x85, 0x26, 0xAD, 0x02, 
+	0x5C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x29, 0xF0, 
+	0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, 0x21, 
+	0x8E, 0x00, 0x5C, 0x64, 0x29, 0x4C, 0xF7, 0x3B, 
+	0xA6, 0x28, 0xE4, 0x27, 0xF0, 0x13, 0xA5, 0x26, 
+	0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x08, 0xD0, 
+	0x08, 0xBD, 0x00, 0x05, 0x8D, 0x00, 0x5C, 0xE6, 
+	0x28, 0xAD, 0x02, 0x64, 0x89, 0x08, 0xF0, 0x3B, 
+	0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 0x64, 0xD0, 
+	0x32, 0xA6, 0x30, 0xA9, 0x01, 0x9D, 0x00, 0x14, 
+	0xA9, 0x01, 0x9D, 0x00, 0x0D, 0xE8, 0xE4, 0x31, 
+	0xF0, 0x02, 0x86, 0x30, 0x4C, 0x39, 0x3C, 0xA6, 
+	0x30, 0xAD, 0x00, 0x64, 0x9D, 0x00, 0x0D, 0x9E, 
+	0x00, 0x14, 0xE8, 0xE4, 0x31, 0xF0, 0x02, 0x86, 
+	0x30, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 0x04, 0xA5, 
+	0x3B, 0x85, 0x32, 0xAD, 0x02, 0x64, 0x29, 0x10, 
+	0xF0, 0x2C, 0xA6, 0x35, 0xF0, 0x0F, 0xAD, 0x02, 
+	0x7C, 0x29, 0x10, 0xD0, 0x21, 0x8E, 0x00, 0x64, 
+	0x64, 0x35, 0x4C, 0x6C, 0x3C, 0xA6, 0x34, 0xE4, 
+	0x33, 0xF0, 0x13, 0xA5, 0x32, 0xD0, 0x0F, 0xAD, 
+	0x02, 0x7C, 0x29, 0x10, 0xD0, 0x08, 0xBD, 0x00, 
+	0x06, 0x8D, 0x00, 0x64, 0xE6, 0x34, 0xAD, 0x02, 
+	0x6C, 0x89, 0x08, 0xF0, 0x3B, 0x89, 0x02, 0xF0, 
+	0x1B, 0xAD, 0x00, 0x6C, 0xD0, 0x32, 0xA6, 0x3C, 
+	0xA9, 0x01, 0x9D, 0x00, 0x15, 0xA9, 0x01, 0x9D, 
+	0x00, 0x0E, 0xE8, 0xE4, 0x3D, 0xF0, 0x02, 0x86, 
+	0x3C, 0x4C, 0xAE, 0x3C, 0xA6, 0x3C, 0xAD, 0x00, 
+	0x6C, 0x9D, 0x00, 0x0E, 0x9E, 0x00, 0x15, 0xE8, 
+	0xE4, 0x3D, 0xF0, 0x02, 0x86, 0x3C, 0x29, 0x7F, 
+	0xC9, 0x13, 0xD0, 0x04, 0xA5, 0x47, 0x85, 0x3E, 
+	0xAD, 0x02, 0x6C, 0x29, 0x10, 0xF0, 0x2C, 0xA6, 
+	0x41, 0xF0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x20, 
+	0xD0, 0x21, 0x8E, 0x00, 0x6C, 0x64, 0x41, 0x4C, 
+	0xE1, 0x3C, 0xA6, 0x40, 0xE4, 0x3F, 0xF0, 0x13, 
+	0xA5, 0x3E, 0xD0, 0x0F, 0xAD, 0x02, 0x7C, 0x29, 
+	0x20, 0xD0, 0x08, 0xBD, 0x00, 0x07, 0x8D, 0x00, 
+	0x6C, 0xE6, 0x40, 0xAD, 0x02, 0x74, 0x89, 0x08, 
+	0xF0, 0x3B, 0x89, 0x02, 0xF0, 0x1B, 0xAD, 0x00, 
+	0x74, 0xD0, 0x32, 0xA6, 0x48, 0xA9, 0x01, 0x9D, 
+	0x00, 0x16, 0xA9, 0x01, 0x9D, 0x00, 0x0F, 0xE8, 
+	0xE4, 0x49, 0xF0, 0x02, 0x86, 0x48, 0x4C, 0x23, 
+	0x3D, 0xA6, 0x48, 0xAD, 0x00, 0x74, 0x9D, 0x00, 
+	0x0F, 0x9E, 0x00, 0x16, 0xE8, 0xE4, 0x49, 0xF0, 
+	0x02, 0x86, 0x48, 0x29, 0x7F, 0xC9, 0x13, 0xD0, 
+	0x04, 0xA5, 0x53, 0x85, 0x4A, 0xAD, 0x02, 0x74, 
+	0x29, 0x10, 0xF0, 0x2C, 0xA6, 0x4D, 0xF0, 0x0F, 
+	0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x21, 0x8E, 
+	0x00, 0x74, 0x64, 0x4D, 0x4C, 0x56, 0x3D, 0xA6, 
+	0x4C, 0xE4, 0x4B, 0xF0, 0x13, 0xA5, 0x4A, 0xD0, 
+	0x0F, 0xAD, 0x02, 0x7C, 0x29, 0x40, 0xD0, 0x08, 
+	0xBD, 0x00, 0x08, 0x8D, 0x00, 0x74, 0xE6, 0x4C, 
+	0x60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
+	0xFF, 0xFF, 0xFF, 0xFF, 0xD0, 0xD0, 0x00, 0x38, 
+	0xCE, 0xC0, 
+};
diff --git a/drivers/staging/generic_serial/sx.c b/drivers/staging/generic_serial/sx.c
new file mode 100644
index 0000000..1291462
--- /dev/null
+++ b/drivers/staging/generic_serial/sx.c
@@ -0,0 +1,2894 @@
+/* sx.c -- driver for the Specialix SX series cards. 
+ *
+ *  This driver will also support the older SI, and XIO cards.
+ *
+ *
+ *   (C) 1998 - 2004  R.E.Wolff@BitWizard.nl
+ *
+ *  Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
+ *  version of this driver. Some fragments may have been copied. (none
+ *  yet :-)
+ *
+ * Specialix pays for the development and support of this driver.
+ * Please DO contact support@specialix.co.uk if you require
+ * support. But please read the documentation (sx.txt) first.
+ *
+ *
+ *
+ *      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.
+ *
+ * Revision history:
+ * Revision 1.33  2000/03/09 10:00:00  pvdl,wolff
+ * - Fixed module and port counting
+ * - Fixed signal handling
+ * - Fixed an Ooops
+ * 
+ * Revision 1.32  2000/03/07 09:00:00  wolff,pvdl
+ * - Fixed some sx_dprintk typos
+ * - added detection for an invalid board/module configuration
+ *
+ * Revision 1.31  2000/03/06 12:00:00  wolff,pvdl
+ * - Added support for EISA
+ *
+ * Revision 1.30  2000/01/21 17:43:06  wolff
+ * - Added support for SX+
+ *
+ * Revision 1.26  1999/08/05 15:22:14  wolff
+ * - Port to 2.3.x
+ * - Reformatted to Linus' liking.
+ *
+ * Revision 1.25  1999/07/30 14:24:08  wolff
+ * Had accidentally left "gs_debug" set to "-1" instead of "off" (=0).
+ *
+ * Revision 1.24  1999/07/28 09:41:52  wolff
+ * - I noticed the remark about use-count straying in sx.txt. I checked
+ *   sx_open, and found a few places where that could happen. I hope it's
+ *   fixed now.
+ *
+ * Revision 1.23  1999/07/28 08:56:06  wolff
+ * - Fixed crash when sx_firmware run twice.
+ * - Added sx_slowpoll as a module parameter (I guess nobody really wanted
+ *   to change it from the default... )
+ * - Fixed a stupid editing problem I introduced in 1.22.
+ * - Fixed dropping characters on a termios change.
+ *
+ * Revision 1.22  1999/07/26 21:01:43  wolff
+ * Russell Brown noticed that I had overlooked 4 out of six modem control
+ * signals in sx_getsignals. Ooops.
+ *
+ * Revision 1.21  1999/07/23 09:11:33  wolff
+ * I forgot to free dynamically allocated memory when the driver is unloaded.
+ *
+ * Revision 1.20  1999/07/20 06:25:26  wolff
+ * The "closing wait" wasn't honoured. Thanks to James Griffiths for
+ * reporting this.
+ *
+ * Revision 1.19  1999/07/11 08:59:59  wolff
+ * Fixed an oops in close, when an open was pending. Changed the memtest
+ * a bit. Should also test the board in word-mode, however my card fails the
+ * memtest then. I still have to figure out what is wrong...
+ *
+ * Revision 1.18  1999/06/10 09:38:42  wolff
+ * Changed the format of the firmware revision from %04x to %x.%02x .
+ *
+ * Revision 1.17  1999/06/04 09:44:35  wolff
+ * fixed problem: reference to pci stuff when config_pci was off...
+ * Thanks to Jorge Novo for noticing this.
+ *
+ * Revision 1.16  1999/06/02 08:30:15  wolff
+ * added/removed the workaround for the DCD bug in the Firmware.
+ * A bit more debugging code to locate that...
+ *
+ * Revision 1.15  1999/06/01 11:35:30  wolff
+ * when DCD is left low (floating?), on TA's the firmware first tells us
+ * that DCD is high, but after a short while suddenly comes to the
+ * conclusion that it is low. All this would be fine, if it weren't that
+ * Unix requires us to send a "hangup" signal in that case. This usually
+ * all happens BEFORE the program has had a chance to ioctl the device
+ * into clocal mode..
+ *
+ * Revision 1.14  1999/05/25 11:18:59  wolff
+ * Added PCI-fix.
+ * Added checks for return code of sx_sendcommand.
+ * Don't issue "reconfig" if port isn't open yet. (bit us on TA modules...)
+ *
+ * Revision 1.13  1999/04/29 15:18:01  wolff
+ * Fixed an "oops" that showed on SuSE 6.0 systems.
+ * Activate DTR again after stty 0.
+ *
+ * Revision 1.12  1999/04/29 07:49:52  wolff
+ * Improved "stty 0" handling a bit. (used to change baud to 9600 assuming
+ *     the connection would be dropped anyway. That is not always the case,
+ *     and confuses people).
+ * Told the card to always monitor the modem signals.
+ * Added support for dynamic  gs_debug adjustments.
+ * Now tells the rest of the system the number of ports.
+ *
+ * Revision 1.11  1999/04/24 11:11:30  wolff
+ * Fixed two stupid typos in the memory test.
+ *
+ * Revision 1.10  1999/04/24 10:53:39  wolff
+ * Added some of Christian's suggestions.
+ * Fixed an HW_COOK_IN bug (ISIG was not in I_OTHER. We used to trust the
+ * card to send the signal to the process.....)
+ *
+ * Revision 1.9  1999/04/23 07:26:38  wolff
+ * Included Christian Lademann's 2.0 compile-warning fixes and interrupt
+ *    assignment redesign.
+ * Cleanup of some other stuff.
+ *
+ * Revision 1.8  1999/04/16 13:05:30  wolff
+ * fixed a DCD change unnoticed bug.
+ *
+ * Revision 1.7  1999/04/14 22:19:51  wolff
+ * Fixed typo that showed up in 2.0.x builds (get_user instead of Get_user!)
+ *
+ * Revision 1.6  1999/04/13 18:40:20  wolff
+ * changed misc-minor to 161, as assigned by HPA.
+ *
+ * Revision 1.5  1999/04/13 15:12:25  wolff
+ * Fixed use-count leak when "hangup" occurred.
+ * Added workaround for a stupid-PCIBIOS bug.
+ *
+ *
+ * Revision 1.4  1999/04/01 22:47:40  wolff
+ * Fixed < 1M linux-2.0 problem.
+ * (vremap isn't compatible with ioremap in that case)
+ *
+ * Revision 1.3  1999/03/31 13:45:45  wolff
+ * Firmware loading is now done through a separate IOCTL.
+ *
+ * Revision 1.2  1999/03/28 12:22:29  wolff
+ * rcs cleanup
+ *
+ * Revision 1.1  1999/03/28 12:10:34  wolff
+ * Readying for release on 2.0.x (sorry David, 1.01 becomes 1.1 for RCS). 
+ *
+ * Revision 0.12  1999/03/28 09:20:10  wolff
+ * Fixed problem in 0.11, continueing cleanup.
+ *
+ * Revision 0.11  1999/03/28 08:46:44  wolff
+ * cleanup. Not good.
+ *
+ * Revision 0.10  1999/03/28 08:09:43  wolff
+ * Fixed loosing characters on close.
+ *
+ * Revision 0.9  1999/03/21 22:52:01  wolff
+ * Ported back to 2.2.... (minor things)
+ *
+ * Revision 0.8  1999/03/21 22:40:33  wolff
+ * Port to 2.0
+ *
+ * Revision 0.7  1999/03/21 19:06:34  wolff
+ * Fixed hangup processing.
+ *
+ * Revision 0.6  1999/02/05 08:45:14  wolff
+ * fixed real_raw problems. Inclusion into kernel imminent.
+ *
+ * Revision 0.5  1998/12/21 23:51:06  wolff
+ * Snatched a nasty bug: sx_transmit_chars was getting re-entered, and it
+ * shouldn't have. THATs why I want to have transmit interrupts even when
+ * the buffer is empty.
+ *
+ * Revision 0.4  1998/12/17 09:34:46  wolff
+ * PPP works. ioctl works. Basically works!
+ *
+ * Revision 0.3  1998/12/15 13:05:18  wolff
+ * It works! Wow! Gotta start implementing IOCTL and stuff....
+ *
+ * Revision 0.2  1998/12/01 08:33:53  wolff
+ * moved over to 2.1.130
+ *
+ * Revision 0.1  1998/11/03 21:23:51  wolff
+ * Initial revision. Detects SX card.
+ *
+ * */
+
+#define SX_VERSION	1.33
+
+#include <linux/module.h>
+#include <linux/kdev_t.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/eisa.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* The 3.0.0 version of sxboards/sxwindow.h  uses BYTE and WORD.... */
+#define BYTE u8
+#define WORD u16
+
+/* .... but the 3.0.4 version uses _u8 and _u16. */
+#define _u8 u8
+#define _u16 u16
+
+#include "sxboards.h"
+#include "sxwindow.h"
+
+#include <linux/generic_serial.h>
+#include "sx.h"
+
+/* I don't think that this driver can handle more than 256 ports on
+   one machine. You'll have to increase the number of boards in sx.h
+   if you want more than 4 boards.  */
+
+#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
+#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
+#endif
+
+/* Configurable options: 
+   (Don't be too sure that it'll work if you toggle them) */
+
+/* Am I paranoid or not ? ;-) */
+#undef SX_PARANOIA_CHECK
+
+/* 20 -> 2000 per second. The card should rate-limit interrupts at 100
+   Hz, but it is user configurable. I don't recommend going above 1000
+   Hz. The interrupt ratelimit might trigger if the interrupt is
+   shared with a very active other device. */
+#define IRQ_RATE_LIMIT 20
+
+/* Sharing interrupts is possible now. If the other device wants more
+   than 2000 interrupts per second, we'd gracefully decline further
+   interrupts. That's not what we want. On the other hand, if the
+   other device interrupts 2000 times a second, don't use the SX
+   interrupt. Use polling. */
+#undef IRQ_RATE_LIMIT
+
+#if 0
+/* Not implemented */
+/* 
+ * The following defines are mostly for testing purposes. But if you need
+ * some nice reporting in your syslog, you can define them also.
+ */
+#define SX_REPORT_FIFO
+#define SX_REPORT_OVERRUN
+#endif
+
+/* Function prototypes */
+static void sx_disable_tx_interrupts(void *ptr);
+static void sx_enable_tx_interrupts(void *ptr);
+static void sx_disable_rx_interrupts(void *ptr);
+static void sx_enable_rx_interrupts(void *ptr);
+static int sx_carrier_raised(struct tty_port *port);
+static void sx_shutdown_port(void *ptr);
+static int sx_set_real_termios(void *ptr);
+static void sx_close(void *ptr);
+static int sx_chars_in_buffer(void *ptr);
+static int sx_init_board(struct sx_board *board);
+static int sx_init_portstructs(int nboards, int nports);
+static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
+						unsigned long arg);
+static int sx_init_drivers(void);
+
+static struct tty_driver *sx_driver;
+
+static DEFINE_MUTEX(sx_boards_lock);
+static struct sx_board boards[SX_NBOARDS];
+static struct sx_port *sx_ports;
+static int sx_initialized;
+static int sx_nports;
+static int sx_debug;
+
+/* You can have the driver poll your card. 
+    - Set sx_poll to 1 to poll every timer tick (10ms on Intel). 
+      This is used when the card cannot use an interrupt for some reason.
+
+    - set sx_slowpoll to 100 to do an extra poll once a second (on Intel). If 
+      the driver misses an interrupt (report this if it DOES happen to you!)
+      everything will continue to work.... 
+ */
+static int sx_poll = 1;
+static int sx_slowpoll;
+
+/* The card limits the number of interrupts per second. 
+   At 115k2 "100" should be sufficient. 
+   If you're using higher baudrates, you can increase this...
+ */
+
+static int sx_maxints = 100;
+
+#ifdef CONFIG_ISA
+
+/* These are the only open spaces in my computer. Yours may have more
+   or less.... -- REW 
+   duh: Card at 0xa0000 is possible on HP Netserver?? -- pvdl
+*/
+static int sx_probe_addrs[] = {
+	0xc0000, 0xd0000, 0xe0000,
+	0xc8000, 0xd8000, 0xe8000
+};
+static int si_probe_addrs[] = {
+	0xc0000, 0xd0000, 0xe0000,
+	0xc8000, 0xd8000, 0xe8000, 0xa0000
+};
+static int si1_probe_addrs[] = {
+	0xd0000
+};
+
+#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
+#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
+#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
+
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+#endif
+
+/* Set the mask to all-ones. This alas, only supports 32 interrupts. 
+   Some architectures may need more. */
+static int sx_irqmask = -1;
+
+module_param(sx_poll, int, 0);
+module_param(sx_slowpoll, int, 0);
+module_param(sx_maxints, int, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_irqmask, int, 0);
+
+MODULE_LICENSE("GPL");
+
+static struct real_driver sx_real_driver = {
+	sx_disable_tx_interrupts,
+	sx_enable_tx_interrupts,
+	sx_disable_rx_interrupts,
+	sx_enable_rx_interrupts,
+	sx_shutdown_port,
+	sx_set_real_termios,
+	sx_chars_in_buffer,
+	sx_close,
+};
+
+/* 
+   This driver can spew a whole lot of debugging output at you. If you
+   need maximum performance, you should disable the DEBUG define. To
+   aid in debugging in the field, I'm leaving the compile-time debug
+   features enabled, and disable them "runtime". That allows me to
+   instruct people with problems to enable debugging without requiring
+   them to recompile... 
+*/
+#define DEBUG
+
+#ifdef DEBUG
+#define sx_dprintk(f, str...)	if (sx_debug & f) printk (str)
+#else
+#define sx_dprintk(f, str...)	/* nothing */
+#endif
+
+#define func_enter()	sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__)
+#define func_exit()	sx_dprintk(SX_DEBUG_FLOW, "sx: exit  %s\n",__func__)
+
+#define func_enter2()	sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
+				__func__, port->line)
+
+/* 
+ *  Firmware loader driver specific routines
+ *
+ */
+
+static const struct file_operations sx_fw_fops = {
+	.owner = THIS_MODULE,
+	.unlocked_ioctl = sx_fw_ioctl,
+	.llseek = noop_llseek,
+};
+
+static struct miscdevice sx_fw_device = {
+	SXCTL_MISC_MINOR, "sxctl", &sx_fw_fops
+};
+
+#ifdef SX_PARANOIA_CHECK
+
+/* This doesn't work. Who's paranoid around here? Not me! */
+
+static inline int sx_paranoia_check(struct sx_port const *port,
+				    char *name, const char *routine)
+{
+	static const char *badmagic = KERN_ERR "sx: Warning: bad sx port magic "
+			"number for device %s in %s\n";
+	static const char *badinfo = KERN_ERR "sx: Warning: null sx port for "
+			"device %s in %s\n";
+
+	if (!port) {
+		printk(badinfo, name, routine);
+		return 1;
+	}
+	if (port->magic != SX_MAGIC) {
+		printk(badmagic, name, routine);
+		return 1;
+	}
+
+	return 0;
+}
+#else
+#define sx_paranoia_check(a,b,c) 0
+#endif
+
+/* The timeouts. First try 30 times as fast as possible. Then give
+   the card some time to breathe between accesses. (Otherwise the
+   processor on the card might not be able to access its OWN bus... */
+
+#define TIMEOUT_1 30
+#define TIMEOUT_2 1000000
+
+#ifdef DEBUG
+static void my_hd_io(void __iomem *p, int len)
+{
+	int i, j, ch;
+	unsigned char __iomem *addr = p;
+
+	for (i = 0; i < len; i += 16) {
+		printk("%p ", addr + i);
+		for (j = 0; j < 16; j++) {
+			printk("%02x %s", readb(addr + j + i),
+					(j == 7) ? " " : "");
+		}
+		for (j = 0; j < 16; j++) {
+			ch = readb(addr + j + i);
+			printk("%c", (ch < 0x20) ? '.' :
+					((ch > 0x7f) ? '.' : ch));
+		}
+		printk("\n");
+	}
+}
+static void my_hd(void *p, int len)
+{
+	int i, j, ch;
+	unsigned char *addr = p;
+
+	for (i = 0; i < len; i += 16) {
+		printk("%p ", addr + i);
+		for (j = 0; j < 16; j++) {
+			printk("%02x %s", addr[j + i], (j == 7) ? " " : "");
+		}
+		for (j = 0; j < 16; j++) {
+			ch = addr[j + i];
+			printk("%c", (ch < 0x20) ? '.' :
+					((ch > 0x7f) ? '.' : ch));
+		}
+		printk("\n");
+	}
+}
+#endif
+
+/* This needs redoing for Alpha -- REW -- Done. */
+
+static inline void write_sx_byte(struct sx_board *board, int offset, u8 byte)
+{
+	writeb(byte, board->base + offset);
+}
+
+static inline u8 read_sx_byte(struct sx_board *board, int offset)
+{
+	return readb(board->base + offset);
+}
+
+static inline void write_sx_word(struct sx_board *board, int offset, u16 word)
+{
+	writew(word, board->base + offset);
+}
+
+static inline u16 read_sx_word(struct sx_board *board, int offset)
+{
+	return readw(board->base + offset);
+}
+
+static int sx_busy_wait_eq(struct sx_board *board,
+		int offset, int mask, int correctval)
+{
+	int i;
+
+	func_enter();
+
+	for (i = 0; i < TIMEOUT_1; i++)
+		if ((read_sx_byte(board, offset) & mask) == correctval) {
+			func_exit();
+			return 1;
+		}
+
+	for (i = 0; i < TIMEOUT_2; i++) {
+		if ((read_sx_byte(board, offset) & mask) == correctval) {
+			func_exit();
+			return 1;
+		}
+		udelay(1);
+	}
+
+	func_exit();
+	return 0;
+}
+
+static int sx_busy_wait_neq(struct sx_board *board,
+		int offset, int mask, int badval)
+{
+	int i;
+
+	func_enter();
+
+	for (i = 0; i < TIMEOUT_1; i++)
+		if ((read_sx_byte(board, offset) & mask) != badval) {
+			func_exit();
+			return 1;
+		}
+
+	for (i = 0; i < TIMEOUT_2; i++) {
+		if ((read_sx_byte(board, offset) & mask) != badval) {
+			func_exit();
+			return 1;
+		}
+		udelay(1);
+	}
+
+	func_exit();
+	return 0;
+}
+
+/* 5.6.4 of 6210028 r2.3 */
+static int sx_reset(struct sx_board *board)
+{
+	func_enter();
+
+	if (IS_SX_BOARD(board)) {
+
+		write_sx_byte(board, SX_CONFIG, 0);
+		write_sx_byte(board, SX_RESET, 1); /* Value doesn't matter */
+
+		if (!sx_busy_wait_eq(board, SX_RESET_STATUS, 1, 0)) {
+			printk(KERN_INFO "sx: Card doesn't respond to "
+					"reset...\n");
+			return 0;
+		}
+	} else if (IS_EISA_BOARD(board)) {
+		outb(board->irq << 4, board->eisa_base + 0xc02);
+	} else if (IS_SI1_BOARD(board)) {
+		write_sx_byte(board, SI1_ISA_RESET, 0);	/*value doesn't matter*/
+	} else {
+		/* Gory details of the SI/ISA board */
+		write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_SET);
+		write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_CLEAR);
+		write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_CLEAR);
+		write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_CLEAR);
+		write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_CLEAR);
+		write_sx_byte(board, SI2_ISA_IRQSET, SI2_ISA_IRQSET_CLEAR);
+	}
+
+	func_exit();
+	return 1;
+}
+
+/* This doesn't work on machines where "NULL" isn't 0 */
+/* If you have one of those, someone will need to write 
+   the equivalent of this, which will amount to about 3 lines. I don't
+   want to complicate this right now. -- REW
+   (See, I do write comments every now and then :-) */
+#define OFFSETOF(strct, elem)	((long)&(((struct strct *)NULL)->elem))
+
+#define CHAN_OFFSET(port,elem)	(port->ch_base + OFFSETOF (_SXCHANNEL, elem))
+#define MODU_OFFSET(board,addr,elem)	(addr + OFFSETOF (_SXMODULE, elem))
+#define  BRD_OFFSET(board,elem)	(OFFSETOF (_SXCARD, elem))
+
+#define sx_write_channel_byte(port, elem, val) \
+	write_sx_byte (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_byte(port, elem) \
+	read_sx_byte (port->board, CHAN_OFFSET (port, elem))
+
+#define sx_write_channel_word(port, elem, val) \
+	write_sx_word (port->board, CHAN_OFFSET (port, elem), val)
+
+#define sx_read_channel_word(port, elem) \
+	read_sx_word (port->board, CHAN_OFFSET (port, elem))
+
+#define sx_write_module_byte(board, addr, elem, val) \
+	write_sx_byte (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_byte(board, addr, elem) \
+	read_sx_byte (board, MODU_OFFSET (board, addr, elem))
+
+#define sx_write_module_word(board, addr, elem, val) \
+	write_sx_word (board, MODU_OFFSET (board, addr, elem), val)
+
+#define sx_read_module_word(board, addr, elem) \
+	read_sx_word (board, MODU_OFFSET (board, addr, elem))
+
+#define sx_write_board_byte(board, elem, val) \
+	write_sx_byte (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_byte(board, elem) \
+	read_sx_byte (board, BRD_OFFSET (board, elem))
+
+#define sx_write_board_word(board, elem, val) \
+	write_sx_word (board, BRD_OFFSET (board, elem), val)
+
+#define sx_read_board_word(board, elem) \
+	read_sx_word (board, BRD_OFFSET (board, elem))
+
+static int sx_start_board(struct sx_board *board)
+{
+	if (IS_SX_BOARD(board)) {
+		write_sx_byte(board, SX_CONFIG, SX_CONF_BUSEN);
+	} else if (IS_EISA_BOARD(board)) {
+		write_sx_byte(board, SI2_EISA_OFF, SI2_EISA_VAL);
+		outb((board->irq << 4) | 4, board->eisa_base + 0xc02);
+	} else if (IS_SI1_BOARD(board)) {
+		write_sx_byte(board, SI1_ISA_RESET_CLEAR, 0);
+		write_sx_byte(board, SI1_ISA_INTCL, 0);
+	} else {
+		/* Don't bug me about the clear_set. 
+		   I haven't the foggiest idea what it's about -- REW */
+		write_sx_byte(board, SI2_ISA_RESET, SI2_ISA_RESET_CLEAR);
+		write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+	}
+	return 1;
+}
+
+#define SX_IRQ_REG_VAL(board) \
+	((board->flags & SX_ISA_BOARD) ? (board->irq << 4) : 0)
+
+/* Note. The SX register is write-only. Therefore, we have to enable the
+   bus too. This is a no-op, if you don't mess with this driver... */
+static int sx_start_interrupts(struct sx_board *board)
+{
+
+	/* Don't call this with board->irq == 0 */
+
+	if (IS_SX_BOARD(board)) {
+		write_sx_byte(board, SX_CONFIG, SX_IRQ_REG_VAL(board) |
+				SX_CONF_BUSEN | SX_CONF_HOSTIRQ);
+	} else if (IS_EISA_BOARD(board)) {
+		inb(board->eisa_base + 0xc03);
+	} else if (IS_SI1_BOARD(board)) {
+		write_sx_byte(board, SI1_ISA_INTCL, 0);
+		write_sx_byte(board, SI1_ISA_INTCL_CLEAR, 0);
+	} else {
+		switch (board->irq) {
+		case 11:
+			write_sx_byte(board, SI2_ISA_IRQ11, SI2_ISA_IRQ11_SET);
+			break;
+		case 12:
+			write_sx_byte(board, SI2_ISA_IRQ12, SI2_ISA_IRQ12_SET);
+			break;
+		case 15:
+			write_sx_byte(board, SI2_ISA_IRQ15, SI2_ISA_IRQ15_SET);
+			break;
+		default:
+			printk(KERN_INFO "sx: SI/XIO card doesn't support "
+					"interrupt %d.\n", board->irq);
+			return 0;
+		}
+		write_sx_byte(board, SI2_ISA_INTCLEAR, SI2_ISA_INTCLEAR_SET);
+	}
+
+	return 1;
+}
+
+static int sx_send_command(struct sx_port *port,
+		int command, int mask, int newstat)
+{
+	func_enter2();
+	write_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat), command);
+	func_exit();
+	return sx_busy_wait_eq(port->board, CHAN_OFFSET(port, hi_hstat), mask,
+			newstat);
+}
+
+static char *mod_type_s(int module_type)
+{
+	switch (module_type) {
+	case TA4:
+		return "TA4";
+	case TA8:
+		return "TA8";
+	case TA4_ASIC:
+		return "TA4_ASIC";
+	case TA8_ASIC:
+		return "TA8_ASIC";
+	case MTA_CD1400:
+		return "MTA_CD1400";
+	case SXDC:
+		return "SXDC";
+	default:
+		return "Unknown/invalid";
+	}
+}
+
+static char *pan_type_s(int pan_type)
+{
+	switch (pan_type) {
+	case MOD_RS232DB25:
+		return "MOD_RS232DB25";
+	case MOD_RS232RJ45:
+		return "MOD_RS232RJ45";
+	case MOD_RS422DB25:
+		return "MOD_RS422DB25";
+	case MOD_PARALLEL:
+		return "MOD_PARALLEL";
+	case MOD_2_RS232DB25:
+		return "MOD_2_RS232DB25";
+	case MOD_2_RS232RJ45:
+		return "MOD_2_RS232RJ45";
+	case MOD_2_RS422DB25:
+		return "MOD_2_RS422DB25";
+	case MOD_RS232DB25MALE:
+		return "MOD_RS232DB25MALE";
+	case MOD_2_PARALLEL:
+		return "MOD_2_PARALLEL";
+	case MOD_BLANK:
+		return "empty";
+	default:
+		return "invalid";
+	}
+}
+
+static int mod_compat_type(int module_type)
+{
+	return module_type >> 4;
+}
+
+static void sx_reconfigure_port(struct sx_port *port)
+{
+	if (sx_read_channel_byte(port, hi_hstat) == HS_IDLE_OPEN) {
+		if (sx_send_command(port, HS_CONFIG, -1, HS_IDLE_OPEN) != 1) {
+			printk(KERN_WARNING "sx: Sent reconfigure command, but "
+					"card didn't react.\n");
+		}
+	} else {
+		sx_dprintk(SX_DEBUG_TERMIOS, "sx: Not sending reconfigure: "
+				"port isn't open (%02x).\n",
+				sx_read_channel_byte(port, hi_hstat));
+	}
+}
+
+static void sx_setsignals(struct sx_port *port, int dtr, int rts)
+{
+	int t;
+	func_enter2();
+
+	t = sx_read_channel_byte(port, hi_op);
+	if (dtr >= 0)
+		t = dtr ? (t | OP_DTR) : (t & ~OP_DTR);
+	if (rts >= 0)
+		t = rts ? (t | OP_RTS) : (t & ~OP_RTS);
+	sx_write_channel_byte(port, hi_op, t);
+	sx_dprintk(SX_DEBUG_MODEMSIGNALS, "setsignals: %d/%d\n", dtr, rts);
+
+	func_exit();
+}
+
+static int sx_getsignals(struct sx_port *port)
+{
+	int i_stat, o_stat;
+
+	o_stat = sx_read_channel_byte(port, hi_op);
+	i_stat = sx_read_channel_byte(port, hi_ip);
+
+	sx_dprintk(SX_DEBUG_MODEMSIGNALS, "getsignals: %d/%d  (%d/%d) "
+			"%02x/%02x\n",
+			(o_stat & OP_DTR) != 0, (o_stat & OP_RTS) != 0,
+			port->c_dcd, tty_port_carrier_raised(&port->gs.port),
+			sx_read_channel_byte(port, hi_ip),
+			sx_read_channel_byte(port, hi_state));
+
+	return (((o_stat & OP_DTR) ? TIOCM_DTR : 0) |
+		((o_stat & OP_RTS) ? TIOCM_RTS : 0) |
+		((i_stat & IP_CTS) ? TIOCM_CTS : 0) |
+		((i_stat & IP_DCD) ? TIOCM_CAR : 0) |
+		((i_stat & IP_DSR) ? TIOCM_DSR : 0) |
+		((i_stat & IP_RI) ? TIOCM_RNG : 0));
+}
+
+static void sx_set_baud(struct sx_port *port)
+{
+	int t;
+
+	if (port->board->ta_type == MOD_SXDC) {
+		switch (port->gs.baud) {
+			/* Save some typing work... */
+#define e(x) case x: t = BAUD_ ## x; break
+			e(50);
+			e(75);
+			e(110);
+			e(150);
+			e(200);
+			e(300);
+			e(600);
+			e(1200);
+			e(1800);
+			e(2000);
+			e(2400);
+			e(4800);
+			e(7200);
+			e(9600);
+			e(14400);
+			e(19200);
+			e(28800);
+			e(38400);
+			e(56000);
+			e(57600);
+			e(64000);
+			e(76800);
+			e(115200);
+			e(128000);
+			e(150000);
+			e(230400);
+			e(256000);
+			e(460800);
+			e(921600);
+		case 134:
+			t = BAUD_134_5;
+			break;
+		case 0:
+			t = -1;
+			break;
+		default:
+			/* Can I return "invalid"? */
+			t = BAUD_9600;
+			printk(KERN_INFO "sx: unsupported baud rate: %d.\n",
+					port->gs.baud);
+			break;
+		}
+#undef e
+		if (t > 0) {
+/* The baud rate is not set to 0, so we're enabeling DTR... -- REW */
+			sx_setsignals(port, 1, -1);
+			/* XXX This is not TA & MTA compatible */
+			sx_write_channel_byte(port, hi_csr, 0xff);
+
+			sx_write_channel_byte(port, hi_txbaud, t);
+			sx_write_channel_byte(port, hi_rxbaud, t);
+		} else {
+			sx_setsignals(port, 0, -1);
+		}
+	} else {
+		switch (port->gs.baud) {
+#define e(x) case x: t = CSR_ ## x; break
+			e(75);
+			e(150);
+			e(300);
+			e(600);
+			e(1200);
+			e(2400);
+			e(4800);
+			e(1800);
+			e(9600);
+			e(19200);
+			e(57600);
+			e(38400);
+/* TA supports 110, but not 115200, MTA supports 115200, but not 110 */
+		case 110:
+			if (port->board->ta_type == MOD_TA) {
+				t = CSR_110;
+				break;
+			} else {
+				t = CSR_9600;
+				printk(KERN_INFO "sx: Unsupported baud rate: "
+						"%d.\n", port->gs.baud);
+				break;
+			}
+		case 115200:
+			if (port->board->ta_type == MOD_TA) {
+				t = CSR_9600;
+				printk(KERN_INFO "sx: Unsupported baud rate: "
+						"%d.\n", port->gs.baud);
+				break;
+			} else {
+				t = CSR_110;
+				break;
+			}
+		case 0:
+			t = -1;
+			break;
+		default:
+			t = CSR_9600;
+			printk(KERN_INFO "sx: Unsupported baud rate: %d.\n",
+					port->gs.baud);
+			break;
+		}
+#undef e
+		if (t >= 0) {
+			sx_setsignals(port, 1, -1);
+			sx_write_channel_byte(port, hi_csr, t * 0x11);
+		} else {
+			sx_setsignals(port, 0, -1);
+		}
+	}
+}
+
+/* Simon Allen's version of this routine was 225 lines long. 85 is a lot
+   better. -- REW */
+
+static int sx_set_real_termios(void *ptr)
+{
+	struct sx_port *port = ptr;
+
+	func_enter2();
+
+	if (!port->gs.port.tty)
+		return 0;
+
+	/* What is this doing here? -- REW
+	   Ha! figured it out. It is to allow you to get DTR active again
+	   if you've dropped it with stty 0. Moved to set_baud, where it
+	   belongs (next to the drop dtr if baud == 0) -- REW */
+	/* sx_setsignals (port, 1, -1); */
+
+	sx_set_baud(port);
+
+#define CFLAG port->gs.port.tty->termios->c_cflag
+	sx_write_channel_byte(port, hi_mr1,
+			(C_PARENB(port->gs.port.tty) ? MR1_WITH : MR1_NONE) |
+			(C_PARODD(port->gs.port.tty) ? MR1_ODD : MR1_EVEN) |
+			(C_CRTSCTS(port->gs.port.tty) ? MR1_RTS_RXFLOW : 0) |
+			(((CFLAG & CSIZE) == CS8) ? MR1_8_BITS : 0) |
+			(((CFLAG & CSIZE) == CS7) ? MR1_7_BITS : 0) |
+			(((CFLAG & CSIZE) == CS6) ? MR1_6_BITS : 0) |
+			(((CFLAG & CSIZE) == CS5) ? MR1_5_BITS : 0));
+
+	sx_write_channel_byte(port, hi_mr2,
+			(C_CRTSCTS(port->gs.port.tty) ? MR2_CTS_TXFLOW : 0) |
+			(C_CSTOPB(port->gs.port.tty) ? MR2_2_STOP :
+			MR2_1_STOP));
+
+	switch (CFLAG & CSIZE) {
+	case CS8:
+		sx_write_channel_byte(port, hi_mask, 0xff);
+		break;
+	case CS7:
+		sx_write_channel_byte(port, hi_mask, 0x7f);
+		break;
+	case CS6:
+		sx_write_channel_byte(port, hi_mask, 0x3f);
+		break;
+	case CS5:
+		sx_write_channel_byte(port, hi_mask, 0x1f);
+		break;
+	default:
+		printk(KERN_INFO "sx: Invalid wordsize: %u\n",
+			(unsigned int)CFLAG & CSIZE);
+		break;
+	}
+
+	sx_write_channel_byte(port, hi_prtcl,
+			(I_IXON(port->gs.port.tty) ? SP_TXEN : 0) |
+			(I_IXOFF(port->gs.port.tty) ? SP_RXEN : 0) |
+			(I_IXANY(port->gs.port.tty) ? SP_TANY : 0) | SP_DCEN);
+
+	sx_write_channel_byte(port, hi_break,
+			(I_IGNBRK(port->gs.port.tty) ? BR_IGN : 0 |
+			I_BRKINT(port->gs.port.tty) ? BR_INT : 0));
+
+	sx_write_channel_byte(port, hi_txon, START_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_rxon, START_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_txoff, STOP_CHAR(port->gs.port.tty));
+	sx_write_channel_byte(port, hi_rxoff, STOP_CHAR(port->gs.port.tty));
+
+	sx_reconfigure_port(port);
+
+	/* Tell line discipline whether we will do input cooking */
+	if (I_OTHER(port->gs.port.tty)) {
+		clear_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
+	} else {
+		set_bit(TTY_HW_COOK_IN, &port->gs.port.tty->flags);
+	}
+	sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+			(unsigned int)port->gs.port.tty->termios->c_iflag,
+			I_OTHER(port->gs.port.tty));
+
+/* Tell line discipline whether we will do output cooking.
+ * If OPOST is set and no other output flags are set then we can do output
+ * processing.  Even if only *one* other flag in the O_OTHER group is set
+ * we do cooking in software.
+ */
+	if (O_OPOST(port->gs.port.tty) && !O_OTHER(port->gs.port.tty)) {
+		set_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
+	} else {
+		clear_bit(TTY_HW_COOK_OUT, &port->gs.port.tty->flags);
+	}
+	sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+			(unsigned int)port->gs.port.tty->termios->c_oflag,
+			O_OTHER(port->gs.port.tty));
+	/* port->c_dcd = sx_get_CD (port); */
+	func_exit();
+	return 0;
+}
+
+/* ********************************************************************** *
+ *                   the interrupt related routines                       *
+ * ********************************************************************** */
+
+/* Note:
+   Other drivers use the macro "MIN" to calculate how much to copy.
+   This has the disadvantage that it will evaluate parts twice. That's
+   expensive when it's IO (and the compiler cannot optimize those away!).
+   Moreover, I'm not sure that you're race-free. 
+
+   I assign a value, and then only allow the value to decrease. This
+   is always safe. This makes the code a few lines longer, and you
+   know I'm dead against that, but I think it is required in this
+   case.  */
+
+static void sx_transmit_chars(struct sx_port *port)
+{
+	int c;
+	int tx_ip;
+	int txroom;
+
+	func_enter2();
+	sx_dprintk(SX_DEBUG_TRANSMIT, "Port %p: transmit %d chars\n",
+			port, port->gs.xmit_cnt);
+
+	if (test_and_set_bit(SX_PORT_TRANSMIT_LOCK, &port->locks)) {
+		return;
+	}
+
+	while (1) {
+		c = port->gs.xmit_cnt;
+
+		sx_dprintk(SX_DEBUG_TRANSMIT, "Copying %d ", c);
+		tx_ip = sx_read_channel_byte(port, hi_txipos);
+
+		/* Took me 5 minutes to deduce this formula. 
+		   Luckily it is literally in the manual in section 6.5.4.3.5 */
+		txroom = (sx_read_channel_byte(port, hi_txopos) - tx_ip - 1) &
+				0xff;
+
+		/* Don't copy more bytes than there is room for in the buffer */
+		if (c > txroom)
+			c = txroom;
+		sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, txroom);
+
+		/* Don't copy past the end of the hardware transmit buffer */
+		if (c > 0x100 - tx_ip)
+			c = 0x100 - tx_ip;
+
+		sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%d) ", c, 0x100 - tx_ip);
+
+		/* Don't copy pas the end of the source buffer */
+		if (c > SERIAL_XMIT_SIZE - port->gs.xmit_tail)
+			c = SERIAL_XMIT_SIZE - port->gs.xmit_tail;
+
+		sx_dprintk(SX_DEBUG_TRANSMIT, " %d(%ld) \n",
+				c, SERIAL_XMIT_SIZE - port->gs.xmit_tail);
+
+		/* If for one reason or another, we can't copy more data, we're
+		   done! */
+		if (c == 0)
+			break;
+
+		memcpy_toio(port->board->base + CHAN_OFFSET(port, hi_txbuf) +
+			tx_ip, port->gs.xmit_buf + port->gs.xmit_tail, c);
+
+		/* Update the pointer in the card */
+		sx_write_channel_byte(port, hi_txipos, (tx_ip + c) & 0xff);
+
+		/* Update the kernel buffer end */
+		port->gs.xmit_tail = (port->gs.xmit_tail + c) &
+				(SERIAL_XMIT_SIZE - 1);
+
+		/* This one last. (this is essential)
+		   It would allow others to start putting more data into the
+		   buffer! */
+		port->gs.xmit_cnt -= c;
+	}
+
+	if (port->gs.xmit_cnt == 0) {
+		sx_disable_tx_interrupts(port);
+	}
+
+	if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.port.tty) {
+		tty_wakeup(port->gs.port.tty);
+		sx_dprintk(SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
+				port->gs.wakeup_chars);
+	}
+
+	clear_bit(SX_PORT_TRANSMIT_LOCK, &port->locks);
+	func_exit();
+}
+
+/* Note the symmetry between receiving chars and transmitting them!
+   Note: The kernel should have implemented both a receive buffer and
+   a transmit buffer. */
+
+/* Inlined: Called only once. Remove the inline when you add another call */
+static inline void sx_receive_chars(struct sx_port *port)
+{
+	int c;
+	int rx_op;
+	struct tty_struct *tty;
+	int copied = 0;
+	unsigned char *rp;
+
+	func_enter2();
+	tty = port->gs.port.tty;
+	while (1) {
+		rx_op = sx_read_channel_byte(port, hi_rxopos);
+		c = (sx_read_channel_byte(port, hi_rxipos) - rx_op) & 0xff;
+
+		sx_dprintk(SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
+
+		/* Don't copy past the end of the hardware receive buffer */
+		if (rx_op + c > 0x100)
+			c = 0x100 - rx_op;
+
+		sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
+		/* Don't copy more bytes than there is room for in the buffer */
+
+		c = tty_prepare_flip_string(tty, &rp, c);
+
+		sx_dprintk(SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
+		/* If for one reason or another, we can't copy more data, we're done! */
+		if (c == 0)
+			break;
+
+		sx_dprintk(SX_DEBUG_RECEIVE, "Copying over %d chars. First is "
+				"%d at %lx\n", c, read_sx_byte(port->board,
+					CHAN_OFFSET(port, hi_rxbuf) + rx_op),
+				CHAN_OFFSET(port, hi_rxbuf));
+		memcpy_fromio(rp, port->board->base +
+				CHAN_OFFSET(port, hi_rxbuf) + rx_op, c);
+
+		/* This one last. ( Not essential.)
+		   It allows the card to start putting more data into the
+		   buffer!
+		   Update the pointer in the card */
+		sx_write_channel_byte(port, hi_rxopos, (rx_op + c) & 0xff);
+
+		copied += c;
+	}
+	if (copied) {
+		struct timeval tv;
+
+		do_gettimeofday(&tv);
+		sx_dprintk(SX_DEBUG_RECEIVE, "pushing flipq port %d (%3d "
+				"chars): %d.%06d  (%d/%d)\n", port->line,
+				copied, (int)(tv.tv_sec % 60), (int)tv.tv_usec,
+				tty->raw, tty->real_raw);
+
+		/* Tell the rest of the system the news. Great news. New
+		   characters! */
+		tty_flip_buffer_push(tty);
+		/*    tty_schedule_flip (tty); */
+	}
+
+	func_exit();
+}
+
+/* Inlined: it is called only once. Remove the inline if you add another 
+   call */
+static inline void sx_check_modem_signals(struct sx_port *port)
+{
+	int hi_state;
+	int c_dcd;
+
+	hi_state = sx_read_channel_byte(port, hi_state);
+	sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Checking modem signals (%d/%d)\n",
+			port->c_dcd, tty_port_carrier_raised(&port->gs.port));
+
+	if (hi_state & ST_BREAK) {
+		hi_state &= ~ST_BREAK;
+		sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a break.\n");
+		sx_write_channel_byte(port, hi_state, hi_state);
+		gs_got_break(&port->gs);
+	}
+	if (hi_state & ST_DCD) {
+		hi_state &= ~ST_DCD;
+		sx_dprintk(SX_DEBUG_MODEMSIGNALS, "got a DCD change.\n");
+		sx_write_channel_byte(port, hi_state, hi_state);
+		c_dcd = tty_port_carrier_raised(&port->gs.port);
+		sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD is now %d\n", c_dcd);
+		if (c_dcd != port->c_dcd) {
+			port->c_dcd = c_dcd;
+			if (tty_port_carrier_raised(&port->gs.port)) {
+				/* DCD went UP */
+				if ((sx_read_channel_byte(port, hi_hstat) !=
+						HS_IDLE_CLOSED) &&
+						!(port->gs.port.tty->termios->
+							c_cflag & CLOCAL)) {
+					/* Are we blocking in open? */
+					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+						"active, unblocking open\n");
+					wake_up_interruptible(&port->gs.port.
+							open_wait);
+				} else {
+					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+						"raised. Ignoring.\n");
+				}
+			} else {
+				/* DCD went down! */
+				if (!(port->gs.port.tty->termios->c_cflag & CLOCAL)){
+					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+						"dropped. hanging up....\n");
+					tty_hangup(port->gs.port.tty);
+				} else {
+					sx_dprintk(SX_DEBUG_MODEMSIGNALS, "DCD "
+						"dropped. ignoring.\n");
+				}
+			}
+		} else {
+			sx_dprintk(SX_DEBUG_MODEMSIGNALS, "Hmmm. card told us "
+				"DCD changed, but it didn't.\n");
+		}
+	}
+}
+
+/* This is what an interrupt routine should look like. 
+ * Small, elegant, clear.
+ */
+
+static irqreturn_t sx_interrupt(int irq, void *ptr)
+{
+	struct sx_board *board = ptr;
+	struct sx_port *port;
+	int i;
+
+	func_enter();
+	sx_dprintk(SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq,
+			board->irq);
+
+	/* AAargh! The order in which to do these things is essential and
+	   not trivial. 
+
+	   - Rate limit goes before "recursive". Otherwise a series of
+	   recursive calls will hang the machine in the interrupt routine.
+
+	   - hardware twiddling goes before "recursive". Otherwise when we
+	   poll the card, and a recursive interrupt happens, we won't
+	   ack the card, so it might keep on interrupting us. (especially
+	   level sensitive interrupt systems like PCI).
+
+	   - Rate limit goes before hardware twiddling. Otherwise we won't
+	   catch a card that has gone bonkers.
+
+	   - The "initialized" test goes after the hardware twiddling. Otherwise
+	   the card will stick us in the interrupt routine again.
+
+	   - The initialized test goes before recursive. 
+	 */
+
+#ifdef IRQ_RATE_LIMIT
+	/* Aaargh! I'm ashamed. This costs more lines-of-code than the
+	   actual interrupt routine!. (Well, used to when I wrote that
+	   comment) */
+	{
+		static int lastjif;
+		static int nintr = 0;
+
+		if (lastjif == jiffies) {
+			if (++nintr > IRQ_RATE_LIMIT) {
+				free_irq(board->irq, board);
+				printk(KERN_ERR "sx: Too many interrupts. "
+						"Turning off interrupt %d.\n",
+						board->irq);
+			}
+		} else {
+			lastjif = jiffies;
+			nintr = 0;
+		}
+	}
+#endif
+
+	if (board->irq == irq) {
+		/* Tell the card we've noticed the interrupt. */
+
+		sx_write_board_word(board, cc_int_pending, 0);
+		if (IS_SX_BOARD(board)) {
+			write_sx_byte(board, SX_RESET_IRQ, 1);
+		} else if (IS_EISA_BOARD(board)) {
+			inb(board->eisa_base + 0xc03);
+			write_sx_word(board, 8, 0);
+		} else {
+			write_sx_byte(board, SI2_ISA_INTCLEAR,
+					SI2_ISA_INTCLEAR_CLEAR);
+			write_sx_byte(board, SI2_ISA_INTCLEAR,
+					SI2_ISA_INTCLEAR_SET);
+		}
+	}
+
+	if (!sx_initialized)
+		return IRQ_HANDLED;
+	if (!(board->flags & SX_BOARD_INITIALIZED))
+		return IRQ_HANDLED;
+
+	if (test_and_set_bit(SX_BOARD_INTR_LOCK, &board->locks)) {
+		printk(KERN_ERR "Recursive interrupt! (%d)\n", board->irq);
+		return IRQ_HANDLED;
+	}
+
+	for (i = 0; i < board->nports; i++) {
+		port = &board->ports[i];
+		if (port->gs.port.flags & GS_ACTIVE) {
+			if (sx_read_channel_byte(port, hi_state)) {
+				sx_dprintk(SX_DEBUG_INTERRUPTS, "Port %d: "
+						"modem signal change?... \n",i);
+				sx_check_modem_signals(port);
+			}
+			if (port->gs.xmit_cnt) {
+				sx_transmit_chars(port);
+			}
+			if (!(port->gs.port.flags & SX_RX_THROTTLE)) {
+				sx_receive_chars(port);
+			}
+		}
+	}
+
+	clear_bit(SX_BOARD_INTR_LOCK, &board->locks);
+
+	sx_dprintk(SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq,
+			board->irq);
+	func_exit();
+	return IRQ_HANDLED;
+}
+
+static void sx_pollfunc(unsigned long data)
+{
+	struct sx_board *board = (struct sx_board *)data;
+
+	func_enter();
+
+	sx_interrupt(0, board);
+
+	mod_timer(&board->timer, jiffies + sx_poll);
+	func_exit();
+}
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *              interface with the generic_serial driver                  *
+ * ********************************************************************** */
+
+/* Ehhm. I don't know how to fiddle with interrupts on the SX card. --REW */
+/* Hmm. Ok I figured it out. You don't.  */
+
+static void sx_disable_tx_interrupts(void *ptr)
+{
+	struct sx_port *port = ptr;
+	func_enter2();
+
+	port->gs.port.flags &= ~GS_TX_INTEN;
+
+	func_exit();
+}
+
+static void sx_enable_tx_interrupts(void *ptr)
+{
+	struct sx_port *port = ptr;
+	int data_in_buffer;
+	func_enter2();
+
+	/* First transmit the characters that we're supposed to */
+	sx_transmit_chars(port);
+
+	/* The sx card will never interrupt us if we don't fill the buffer
+	   past 25%. So we keep considering interrupts off if that's the case. */
+	data_in_buffer = (sx_read_channel_byte(port, hi_txipos) -
+			  sx_read_channel_byte(port, hi_txopos)) & 0xff;
+
+	/* XXX Must be "HIGH_WATER" for SI card according to doc. */
+	if (data_in_buffer < LOW_WATER)
+		port->gs.port.flags &= ~GS_TX_INTEN;
+
+	func_exit();
+}
+
+static void sx_disable_rx_interrupts(void *ptr)
+{
+	/*  struct sx_port *port = ptr; */
+	func_enter();
+
+	func_exit();
+}
+
+static void sx_enable_rx_interrupts(void *ptr)
+{
+	/*  struct sx_port *port = ptr; */
+	func_enter();
+
+	func_exit();
+}
+
+/* Jeez. Isn't this simple? */
+static int sx_carrier_raised(struct tty_port *port)
+{
+	struct sx_port *sp = container_of(port, struct sx_port, gs.port);
+	return ((sx_read_channel_byte(sp, hi_ip) & IP_DCD) != 0);
+}
+
+/* Jeez. Isn't this simple? */
+static int sx_chars_in_buffer(void *ptr)
+{
+	struct sx_port *port = ptr;
+	func_enter2();
+
+	func_exit();
+	return ((sx_read_channel_byte(port, hi_txipos) -
+		 sx_read_channel_byte(port, hi_txopos)) & 0xff);
+}
+
+static void sx_shutdown_port(void *ptr)
+{
+	struct sx_port *port = ptr;
+
+	func_enter();
+
+	port->gs.port.flags &= ~GS_ACTIVE;
+	if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
+		sx_setsignals(port, 0, 0);
+		sx_reconfigure_port(port);
+	}
+
+	func_exit();
+}
+
+/* ********************************************************************** *
+ *                Here are the routines that actually                     *
+ *               interface with the rest of the system                    *
+ * ********************************************************************** */
+
+static int sx_open(struct tty_struct *tty, struct file *filp)
+{
+	struct sx_port *port;
+	int retval, line;
+	unsigned long flags;
+
+	func_enter();
+
+	if (!sx_initialized) {
+		return -EIO;
+	}
+
+	line = tty->index;
+	sx_dprintk(SX_DEBUG_OPEN, "%d: opening line %d. tty=%p ctty=%p, "
+			"np=%d)\n", task_pid_nr(current), line, tty,
+			current->signal->tty, sx_nports);
+
+	if ((line < 0) || (line >= SX_NPORTS) || (line >= sx_nports))
+		return -ENODEV;
+
+	port = &sx_ports[line];
+	port->c_dcd = 0; /* Make sure that the first interrupt doesn't detect a
+			    1 -> 0 transition. */
+
+	sx_dprintk(SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+
+	spin_lock_irqsave(&port->gs.driver_lock, flags);
+
+	tty->driver_data = port;
+	port->gs.port.tty = tty;
+	port->gs.port.count++;
+	spin_unlock_irqrestore(&port->gs.driver_lock, flags);
+
+	sx_dprintk(SX_DEBUG_OPEN, "starting port\n");
+
+	/*
+	 * Start up serial port
+	 */
+	retval = gs_init_port(&port->gs);
+	sx_dprintk(SX_DEBUG_OPEN, "done gs_init\n");
+	if (retval) {
+		port->gs.port.count--;
+		return retval;
+	}
+
+	port->gs.port.flags |= GS_ACTIVE;
+	if (port->gs.port.count <= 1)
+		sx_setsignals(port, 1, 1);
+
+#if 0
+	if (sx_debug & SX_DEBUG_OPEN)
+		my_hd(port, sizeof(*port));
+#else
+	if (sx_debug & SX_DEBUG_OPEN)
+		my_hd_io(port->board->base + port->ch_base, sizeof(*port));
+#endif
+
+	if (port->gs.port.count <= 1) {
+		if (sx_send_command(port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+			printk(KERN_ERR "sx: Card didn't respond to LOPEN "
+					"command.\n");
+			spin_lock_irqsave(&port->gs.driver_lock, flags);
+			port->gs.port.count--;
+			spin_unlock_irqrestore(&port->gs.driver_lock, flags);
+			return -EIO;
+		}
+	}
+
+	retval = gs_block_til_ready(port, filp);
+	sx_dprintk(SX_DEBUG_OPEN, "Block til ready returned %d. Count=%d\n",
+			retval, port->gs.port.count);
+
+	if (retval) {
+/*
+ * Don't lower gs.port.count here because sx_close() will be called later
+ */
+
+		return retval;
+	}
+	/* tty->low_latency = 1; */
+
+	port->c_dcd = sx_carrier_raised(&port->gs.port);
+	sx_dprintk(SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+
+	func_exit();
+	return 0;
+
+}
+
+static void sx_close(void *ptr)
+{
+	struct sx_port *port = ptr;
+	/* Give the port 5 seconds to close down. */
+	int to = 5 * HZ;
+
+	func_enter();
+
+	sx_setsignals(port, 0, 0);
+	sx_reconfigure_port(port);
+	sx_send_command(port, HS_CLOSE, 0, 0);
+
+	while (to-- && (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED))
+		if (msleep_interruptible(10))
+			break;
+	if (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) {
+		if (sx_send_command(port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED)
+				!= 1) {
+			printk(KERN_ERR "sx: sent the force_close command, but "
+					"card didn't react\n");
+		} else
+			sx_dprintk(SX_DEBUG_CLOSE, "sent the force_close "
+					"command.\n");
+	}
+
+	sx_dprintk(SX_DEBUG_CLOSE, "waited %d jiffies for close. count=%d\n",
+			5 * HZ - to - 1, port->gs.port.count);
+
+	if (port->gs.port.count) {
+		sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
+				port->gs.port.count);
+		/*printk("%s SETTING port count to zero: %p count: %d\n",
+				__func__, port, port->gs.port.count);
+		port->gs.port.count = 0;*/
+	}
+
+	func_exit();
+}
+
+/* This is relatively thorough. But then again it is only 20 lines. */
+#define MARCHUP		for (i = min; i < max; i++)
+#define MARCHDOWN	for (i = max - 1; i >= min; i--)
+#define W0		write_sx_byte(board, i, 0x55)
+#define W1		write_sx_byte(board, i, 0xaa)
+#define R0		if (read_sx_byte(board, i) != 0x55) return 1
+#define R1		if (read_sx_byte(board, i) != 0xaa) return 1
+
+/* This memtest takes a human-noticable time. You normally only do it
+   once a boot, so I guess that it is worth it. */
+static int do_memtest(struct sx_board *board, int min, int max)
+{
+	int i;
+
+	/* This is a marchb. Theoretically, marchb catches much more than
+	   simpler tests. In practise, the longer test just catches more
+	   intermittent errors. -- REW
+	   (For the theory behind memory testing see: 
+	   Testing Semiconductor Memories by A.J. van de Goor.) */
+	MARCHUP {
+		W0;
+	}
+	MARCHUP {
+		R0;
+		W1;
+		R1;
+		W0;
+		R0;
+		W1;
+	}
+	MARCHUP {
+		R1;
+		W0;
+		W1;
+	}
+	MARCHDOWN {
+		R1;
+		W0;
+		W1;
+		W0;
+	}
+	MARCHDOWN {
+		R0;
+		W1;
+		W0;
+	}
+
+	return 0;
+}
+
+#undef MARCHUP
+#undef MARCHDOWN
+#undef W0
+#undef W1
+#undef R0
+#undef R1
+
+#define MARCHUP		for (i = min; i < max; i += 2)
+#define MARCHDOWN	for (i = max - 1; i >= min; i -= 2)
+#define W0		write_sx_word(board, i, 0x55aa)
+#define W1		write_sx_word(board, i, 0xaa55)
+#define R0		if (read_sx_word(board, i) != 0x55aa) return 1
+#define R1		if (read_sx_word(board, i) != 0xaa55) return 1
+
+#if 0
+/* This memtest takes a human-noticable time. You normally only do it
+   once a boot, so I guess that it is worth it. */
+static int do_memtest_w(struct sx_board *board, int min, int max)
+{
+	int i;
+
+	MARCHUP {
+		W0;
+	}
+	MARCHUP {
+		R0;
+		W1;
+		R1;
+		W0;
+		R0;
+		W1;
+	}
+	MARCHUP {
+		R1;
+		W0;
+		W1;
+	}
+	MARCHDOWN {
+		R1;
+		W0;
+		W1;
+		W0;
+	}
+	MARCHDOWN {
+		R0;
+		W1;
+		W0;
+	}
+
+	return 0;
+}
+#endif
+
+static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
+							unsigned long arg)
+{
+	long rc = 0;
+	int __user *descr = (int __user *)arg;
+	int i;
+	static struct sx_board *board = NULL;
+	int nbytes, offset;
+	unsigned long data;
+	char *tmp;
+
+	func_enter();
+
+	if (!capable(CAP_SYS_RAWIO))
+		return -EPERM;
+
+	tty_lock();
+
+	sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg);
+
+	if (!board)
+		board = &boards[0];
+	if (board->flags & SX_BOARD_PRESENT) {
+		sx_dprintk(SX_DEBUG_FIRMWARE, "Board present! (%x)\n",
+				board->flags);
+	} else {
+		sx_dprintk(SX_DEBUG_FIRMWARE, "Board not present! (%x) all:",
+				board->flags);
+		for (i = 0; i < SX_NBOARDS; i++)
+			sx_dprintk(SX_DEBUG_FIRMWARE, "<%x> ", boards[i].flags);
+		sx_dprintk(SX_DEBUG_FIRMWARE, "\n");
+		rc = -EIO;
+		goto out;
+	}
+
+	switch (cmd) {
+	case SXIO_SET_BOARD:
+		sx_dprintk(SX_DEBUG_FIRMWARE, "set board to %ld\n", arg);
+		rc = -EIO;
+		if (arg >= SX_NBOARDS)
+			break;
+		sx_dprintk(SX_DEBUG_FIRMWARE, "not out of range\n");
+		if (!(boards[arg].flags & SX_BOARD_PRESENT))
+			break;
+		sx_dprintk(SX_DEBUG_FIRMWARE, ".. and present!\n");
+		board = &boards[arg];
+		rc = 0;
+		/* FIXME: And this does ... nothing?? */
+		break;
+	case SXIO_GET_TYPE:
+		rc = -ENOENT;	/* If we manage to miss one, return error. */
+		if (IS_SX_BOARD(board))
+			rc = SX_TYPE_SX;
+		if (IS_CF_BOARD(board))
+			rc = SX_TYPE_CF;
+		if (IS_SI_BOARD(board))
+			rc = SX_TYPE_SI;
+		if (IS_SI1_BOARD(board))
+			rc = SX_TYPE_SI;
+		if (IS_EISA_BOARD(board))
+			rc = SX_TYPE_SI;
+		sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
+		break;
+	case SXIO_DO_RAMTEST:
+		if (sx_initialized) {	/* Already initialized: better not ramtest the board.  */
+			rc = -EPERM;
+			break;
+		}
+		if (IS_SX_BOARD(board)) {
+			rc = do_memtest(board, 0, 0x7000);
+			if (!rc)
+				rc = do_memtest(board, 0, 0x7000);
+			/*if (!rc) rc = do_memtest_w (board, 0, 0x7000); */
+		} else {
+			rc = do_memtest(board, 0, 0x7ff8);
+			/* if (!rc) rc = do_memtest_w (board, 0, 0x7ff8); */
+		}
+		sx_dprintk(SX_DEBUG_FIRMWARE,
+				"returning memtest result= %ld\n", rc);
+		break;
+	case SXIO_DOWNLOAD:
+		if (sx_initialized) {/* Already initialized */
+			rc = -EEXIST;
+			break;
+		}
+		if (!sx_reset(board)) {
+			rc = -EIO;
+			break;
+		}
+		sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
+
+		tmp = kmalloc(SX_CHUNK_SIZE, GFP_USER);
+		if (!tmp) {
+			rc = -ENOMEM;
+			break;
+		}
+		/* FIXME: check returns */
+		get_user(nbytes, descr++);
+		get_user(offset, descr++);
+		get_user(data, descr++);
+		while (nbytes && data) {
+			for (i = 0; i < nbytes; i += SX_CHUNK_SIZE) {
+				if (copy_from_user(tmp, (char __user *)data + i,
+						(i + SX_CHUNK_SIZE > nbytes) ?
+						nbytes - i : SX_CHUNK_SIZE)) {
+					kfree(tmp);
+					rc = -EFAULT;
+					goto out;
+				}
+				memcpy_toio(board->base2 + offset + i, tmp,
+						(i + SX_CHUNK_SIZE > nbytes) ?
+						nbytes - i : SX_CHUNK_SIZE);
+			}
+
+			get_user(nbytes, descr++);
+			get_user(offset, descr++);
+			get_user(data, descr++);
+		}
+		kfree(tmp);
+		sx_nports += sx_init_board(board);
+		rc = sx_nports;
+		break;
+	case SXIO_INIT:
+		if (sx_initialized) {	/* Already initialized */
+			rc = -EEXIST;
+			break;
+		}
+		/* This is not allowed until all boards are initialized... */
+		for (i = 0; i < SX_NBOARDS; i++) {
+			if ((boards[i].flags & SX_BOARD_PRESENT) &&
+				!(boards[i].flags & SX_BOARD_INITIALIZED)) {
+				rc = -EIO;
+				break;
+			}
+		}
+		for (i = 0; i < SX_NBOARDS; i++)
+			if (!(boards[i].flags & SX_BOARD_PRESENT))
+				break;
+
+		sx_dprintk(SX_DEBUG_FIRMWARE, "initing portstructs, %d boards, "
+				"%d channels, first board: %d ports\n",
+				i, sx_nports, boards[0].nports);
+		rc = sx_init_portstructs(i, sx_nports);
+		sx_init_drivers();
+		if (rc >= 0)
+			sx_initialized++;
+		break;
+	case SXIO_SETDEBUG:
+		sx_debug = arg;
+		break;
+	case SXIO_GETDEBUG:
+		rc = sx_debug;
+		break;
+	case SXIO_GETGSDEBUG:
+	case SXIO_SETGSDEBUG:
+		rc = -EINVAL;
+		break;
+	case SXIO_GETNPORTS:
+		rc = sx_nports;
+		break;
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+out:
+	tty_unlock();
+	func_exit();
+	return rc;
+}
+
+static int sx_break(struct tty_struct *tty, int flag)
+{
+	struct sx_port *port = tty->driver_data;
+	int rv;
+
+	func_enter();
+	tty_lock();
+
+	if (flag)
+		rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
+	else
+		rv = sx_send_command(port, HS_STOP, -1, HS_IDLE_OPEN);
+	if (rv != 1)
+		printk(KERN_ERR "sx: couldn't send break (%x).\n",
+			read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
+	tty_unlock();
+	func_exit();
+	return 0;
+}
+
+static int sx_tiocmget(struct tty_struct *tty)
+{
+	struct sx_port *port = tty->driver_data;
+	return sx_getsignals(port);
+}
+
+static int sx_tiocmset(struct tty_struct *tty,
+					unsigned int set, unsigned int clear)
+{
+	struct sx_port *port = tty->driver_data;
+	int rts = -1, dtr = -1;
+
+	if (set & TIOCM_RTS)
+		rts = 1;
+	if (set & TIOCM_DTR)
+		dtr = 1;
+	if (clear & TIOCM_RTS)
+		rts = 0;
+	if (clear & TIOCM_DTR)
+		dtr = 0;
+
+	sx_setsignals(port, dtr, rts);
+	sx_reconfigure_port(port);
+	return 0;
+}
+
+static int sx_ioctl(struct tty_struct *tty,
+		unsigned int cmd, unsigned long arg)
+{
+	int rc;
+	struct sx_port *port = tty->driver_data;
+	void __user *argp = (void __user *)arg;
+
+	/* func_enter2(); */
+
+	rc = 0;
+	tty_lock();
+	switch (cmd) {
+	case TIOCGSERIAL:
+		rc = gs_getserial(&port->gs, argp);
+		break;
+	case TIOCSSERIAL:
+		rc = gs_setserial(&port->gs, argp);
+		break;
+	default:
+		rc = -ENOIOCTLCMD;
+		break;
+	}
+	tty_unlock();
+
+	/* func_exit(); */
+	return rc;
+}
+
+/* The throttle/unthrottle scheme for the Specialix card is different
+ * from other drivers and deserves some explanation. 
+ * The Specialix hardware takes care of XON/XOFF
+ * and CTS/RTS flow control itself.  This means that all we have to
+ * do when signalled by the upper tty layer to throttle/unthrottle is
+ * to make a note of it here.  When we come to read characters from the
+ * rx buffers on the card (sx_receive_chars()) we look to see if the
+ * upper layer can accept more (as noted here in sx_rx_throt[]). 
+ * If it can't we simply don't remove chars from the cards buffer. 
+ * When the tty layer can accept chars, we again note that here and when
+ * sx_receive_chars() is called it will remove them from the cards buffer.
+ * The card will notice that a ports buffer has drained below some low
+ * water mark and will unflow control the line itself, using whatever
+ * flow control scheme is in use for that port. -- Simon Allen
+ */
+
+static void sx_throttle(struct tty_struct *tty)
+{
+	struct sx_port *port = tty->driver_data;
+
+	func_enter2();
+	/* If the port is using any type of input flow
+	 * control then throttle the port.
+	 */
+	if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
+		port->gs.port.flags |= SX_RX_THROTTLE;
+	}
+	func_exit();
+}
+
+static void sx_unthrottle(struct tty_struct *tty)
+{
+	struct sx_port *port = tty->driver_data;
+
+	func_enter2();
+	/* Always unthrottle even if flow control is not enabled on
+	 * this port in case we disabled flow control while the port
+	 * was throttled
+	 */
+	port->gs.port.flags &= ~SX_RX_THROTTLE;
+	func_exit();
+	return;
+}
+
+/* ********************************************************************** *
+ *                    Here are the initialization routines.               *
+ * ********************************************************************** */
+
+static int sx_init_board(struct sx_board *board)
+{
+	int addr;
+	int chans;
+	int type;
+
+	func_enter();
+
+	/* This is preceded by downloading the download code. */
+
+	board->flags |= SX_BOARD_INITIALIZED;
+
+	if (read_sx_byte(board, 0))
+		/* CF boards may need this. */
+		write_sx_byte(board, 0, 0);
+
+	/* This resets the processor again, to make sure it didn't do any
+	   foolish things while we were downloading the image */
+	if (!sx_reset(board))
+		return 0;
+
+	sx_start_board(board);
+	udelay(10);
+	if (!sx_busy_wait_neq(board, 0, 0xff, 0)) {
+		printk(KERN_ERR "sx: Ooops. Board won't initialize.\n");
+		return 0;
+	}
+
+	/* Ok. So now the processor on the card is running. It gathered
+	   some info for us... */
+	sx_dprintk(SX_DEBUG_INIT, "The sxcard structure:\n");
+	if (sx_debug & SX_DEBUG_INIT)
+		my_hd_io(board->base, 0x10);
+	sx_dprintk(SX_DEBUG_INIT, "the first sx_module structure:\n");
+	if (sx_debug & SX_DEBUG_INIT)
+		my_hd_io(board->base + 0x80, 0x30);
+
+	sx_dprintk(SX_DEBUG_INIT, "init_status: %x, %dk memory, firmware "
+			"V%x.%02x,\n",
+			read_sx_byte(board, 0), read_sx_byte(board, 1),
+			read_sx_byte(board, 5), read_sx_byte(board, 4));
+
+	if (read_sx_byte(board, 0) == 0xff) {
+		printk(KERN_INFO "sx: No modules found. Sorry.\n");
+		board->nports = 0;
+		return 0;
+	}
+
+	chans = 0;
+
+	if (IS_SX_BOARD(board)) {
+		sx_write_board_word(board, cc_int_count, sx_maxints);
+	} else {
+		if (sx_maxints)
+			sx_write_board_word(board, cc_int_count,
+					SI_PROCESSOR_CLOCK / 8 / sx_maxints);
+	}
+
+	/* grab the first module type... */
+	/* board->ta_type = mod_compat_type (read_sx_byte (board, 0x80 + 0x08)); */
+	board->ta_type = mod_compat_type(sx_read_module_byte(board, 0x80,
+				mc_chip));
+
+	/* XXX byteorder */
+	for (addr = 0x80; addr != 0; addr = read_sx_word(board, addr) & 0x7fff){
+		type = sx_read_module_byte(board, addr, mc_chip);
+		sx_dprintk(SX_DEBUG_INIT, "Module at %x: %d channels\n",
+				addr, read_sx_byte(board, addr + 2));
+
+		chans += sx_read_module_byte(board, addr, mc_type);
+
+		sx_dprintk(SX_DEBUG_INIT, "module is an %s, which has %s/%s "
+				"panels\n",
+				mod_type_s(type),
+				pan_type_s(sx_read_module_byte(board, addr,
+						mc_mods) & 0xf),
+				pan_type_s(sx_read_module_byte(board, addr,
+						mc_mods) >> 4));
+
+		sx_dprintk(SX_DEBUG_INIT, "CD1400 versions: %x/%x, ASIC "
+			"version: %x\n",
+			sx_read_module_byte(board, addr, mc_rev1),
+			sx_read_module_byte(board, addr, mc_rev2),
+			sx_read_module_byte(board, addr, mc_mtaasic_rev));
+
+		/* The following combinations are illegal: It should theoretically
+		   work, but timing problems make the bus HANG. */
+
+		if (mod_compat_type(type) != board->ta_type) {
+			printk(KERN_ERR "sx: This is an invalid "
+				"configuration.\nDon't mix TA/MTA/SXDC on the "
+				"same hostadapter.\n");
+			chans = 0;
+			break;
+		}
+		if ((IS_EISA_BOARD(board) ||
+				IS_SI_BOARD(board)) &&
+				(mod_compat_type(type) == 4)) {
+			printk(KERN_ERR	"sx: This is an invalid "
+				"configuration.\nDon't use SXDCs on an SI/XIO "
+				"adapter.\n");
+			chans = 0;
+			break;
+		}
+#if 0				/* Problem fixed: firmware 3.05 */
+		if (IS_SX_BOARD(board) && (type == TA8)) {
+			/* There are some issues with the firmware and the DCD/RTS
+			   lines. It might work if you tie them together or something.
+			   It might also work if you get a newer sx_firmware.   Therefore
+			   this is just a warning. */
+			printk(KERN_WARNING
+			       "sx: The SX host doesn't work too well "
+			       "with the TA8 adapters.\nSpecialix is working on it.\n");
+		}
+#endif
+	}
+
+	if (chans) {
+		if (board->irq > 0) {
+			/* fixed irq, probably PCI */
+			if (sx_irqmask & (1 << board->irq)) {	/* may we use this irq? */
+				if (request_irq(board->irq, sx_interrupt,
+						IRQF_SHARED | IRQF_DISABLED,
+						"sx", board)) {
+					printk(KERN_ERR "sx: Cannot allocate "
+						"irq %d.\n", board->irq);
+					board->irq = 0;
+				}
+			} else
+				board->irq = 0;
+		} else if (board->irq < 0 && sx_irqmask) {
+			/* auto-allocate irq */
+			int irqnr;
+			int irqmask = sx_irqmask & (IS_SX_BOARD(board) ?
+					SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
+			for (irqnr = 15; irqnr > 0; irqnr--)
+				if (irqmask & (1 << irqnr))
+					if (!request_irq(irqnr, sx_interrupt,
+						IRQF_SHARED | IRQF_DISABLED,
+						"sx", board))
+						break;
+			if (!irqnr)
+				printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
+			board->irq = irqnr;
+		} else
+			board->irq = 0;
+
+		if (board->irq) {
+			/* Found a valid interrupt, start up interrupts! */
+			sx_dprintk(SX_DEBUG_INIT, "Using irq %d.\n",
+					board->irq);
+			sx_start_interrupts(board);
+			board->poll = sx_slowpoll;
+			board->flags |= SX_IRQ_ALLOCATED;
+		} else {
+			/* no irq: setup board for polled operation */
+			board->poll = sx_poll;
+			sx_dprintk(SX_DEBUG_INIT, "Using poll-interval %d.\n",
+					board->poll);
+		}
+
+		/* The timer should be initialized anyway: That way we can
+		   safely del_timer it when the module is unloaded. */
+		setup_timer(&board->timer, sx_pollfunc, (unsigned long)board);
+
+		if (board->poll)
+			mod_timer(&board->timer, jiffies + board->poll);
+	} else {
+		board->irq = 0;
+	}
+
+	board->nports = chans;
+	sx_dprintk(SX_DEBUG_INIT, "returning %d ports.", board->nports);
+
+	func_exit();
+	return chans;
+}
+
+static void __devinit printheader(void)
+{
+	static int header_printed;
+
+	if (!header_printed) {
+		printk(KERN_INFO "Specialix SX driver "
+			"(C) 1998/1999 R.E.Wolff@BitWizard.nl\n");
+		printk(KERN_INFO "sx: version " __stringify(SX_VERSION) "\n");
+		header_printed = 1;
+	}
+}
+
+static int __devinit probe_sx(struct sx_board *board)
+{
+	struct vpd_prom vpdp;
+	char *p;
+	int i;
+
+	func_enter();
+
+	if (!IS_CF_BOARD(board)) {
+		sx_dprintk(SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
+				board->base + SX_VPD_ROM);
+
+		if (sx_debug & SX_DEBUG_PROBE)
+			my_hd_io(board->base + SX_VPD_ROM, 0x40);
+
+		p = (char *)&vpdp;
+		for (i = 0; i < sizeof(struct vpd_prom); i++)
+			*p++ = read_sx_byte(board, SX_VPD_ROM + i * 2);
+
+		if (sx_debug & SX_DEBUG_PROBE)
+			my_hd(&vpdp, 0x20);
+
+		sx_dprintk(SX_DEBUG_PROBE, "checking identifier...\n");
+
+		if (strncmp(vpdp.identifier, SX_VPD_IDENT_STRING, 16) != 0) {
+			sx_dprintk(SX_DEBUG_PROBE, "Got non-SX identifier: "
+					"'%s'\n", vpdp.identifier);
+			return 0;
+		}
+	}
+
+	printheader();
+
+	if (!IS_CF_BOARD(board)) {
+		printk(KERN_DEBUG "sx: Found an SX board at %lx\n",
+			board->hw_base);
+		printk(KERN_DEBUG "sx: hw_rev: %d, assembly level: %d, "
+				"uniq ID:%08x, ",
+				vpdp.hwrev, vpdp.hwass, vpdp.uniqid);
+		printk("Manufactured: %d/%d\n", 1970 + vpdp.myear, vpdp.mweek);
+
+		if ((((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) !=
+				SX_PCI_UNIQUEID1) && (((vpdp.uniqid >> 24) &
+				SX_UNIQUEID_MASK) != SX_ISA_UNIQUEID1)) {
+			/* This might be a bit harsh. This was the primary
+			   reason the SX/ISA card didn't work at first... */
+			printk(KERN_ERR "sx: Hmm. Not an SX/PCI or SX/ISA "
+					"card. Sorry: giving up.\n");
+			return (0);
+		}
+
+		if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) ==
+				SX_ISA_UNIQUEID1) {
+			if (((unsigned long)board->hw_base) & 0x8000) {
+				printk(KERN_WARNING "sx: Warning: There may be "
+					"hardware problems with the card at "
+					"%lx.\n", board->hw_base);
+				printk(KERN_WARNING "sx: Read sx.txt for more "
+						"info.\n");
+			}
+		}
+	}
+
+	board->nports = -1;
+
+	/* This resets the processor, and keeps it off the bus. */
+	if (!sx_reset(board))
+		return 0;
+	sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
+
+	func_exit();
+	return 1;
+}
+
+#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
+
+/* Specialix probes for this card at 32k increments from 640k to 16M.
+   I consider machines with less than 16M unlikely nowadays, so I'm
+   not probing above 1Mb. Also, 0xa0000, 0xb0000, are taken by the VGA
+   card. 0xe0000 and 0xf0000 are taken by the BIOS. That only leaves 
+   0xc0000, 0xc8000, 0xd0000 and 0xd8000 . */
+
+static int __devinit probe_si(struct sx_board *board)
+{
+	int i;
+
+	func_enter();
+	sx_dprintk(SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at "
+		"%p.\n", board->hw_base, board->base + SI2_ISA_ID_BASE);
+
+	if (sx_debug & SX_DEBUG_PROBE)
+		my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
+
+	if (!IS_EISA_BOARD(board)) {
+		if (IS_SI1_BOARD(board)) {
+			for (i = 0; i < 8; i++) {
+				write_sx_byte(board, SI2_ISA_ID_BASE + 7 - i,i);
+			}
+		}
+		for (i = 0; i < 8; i++) {
+			if ((read_sx_byte(board, SI2_ISA_ID_BASE + 7 - i) & 7)
+					!= i) {
+				func_exit();
+				return 0;
+			}
+		}
+	}
+
+	/* Now we're pretty much convinced that there is an SI board here, 
+	   but to prevent trouble, we'd better double check that we don't
+	   have an SI1 board when we're probing for an SI2 board.... */
+
+	write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+	if (IS_SI1_BOARD(board)) {
+		/* This should be an SI1 board, which has this
+		   location writable... */
+		if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
+			func_exit();
+			return 0;
+		}
+	} else {
+		/* This should be an SI2 board, which has the bottom
+		   3 bits non-writable... */
+		if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+			func_exit();
+			return 0;
+		}
+	}
+
+	/* Now we're pretty much convinced that there is an SI board here, 
+	   but to prevent trouble, we'd better double check that we don't
+	   have an SI1 board when we're probing for an SI2 board.... */
+
+	write_sx_byte(board, SI2_ISA_ID_BASE, 0x10);
+	if (IS_SI1_BOARD(board)) {
+		/* This should be an SI1 board, which has this
+		   location writable... */
+		if (read_sx_byte(board, SI2_ISA_ID_BASE) != 0x10) {
+			func_exit();
+			return 0;
+		}
+	} else {
+		/* This should be an SI2 board, which has the bottom
+		   3 bits non-writable... */
+		if (read_sx_byte(board, SI2_ISA_ID_BASE) == 0x10) {
+			func_exit();
+			return 0;
+		}
+	}
+
+	printheader();
+
+	printk(KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base);
+	/* Compared to the SX boards, it is a complete guess as to what
+	   this card is up to... */
+
+	board->nports = -1;
+
+	/* This resets the processor, and keeps it off the bus. */
+	if (!sx_reset(board))
+		return 0;
+	sx_dprintk(SX_DEBUG_INIT, "reset the board...\n");
+
+	func_exit();
+	return 1;
+}
+#endif
+
+static const struct tty_operations sx_ops = {
+	.break_ctl = sx_break,
+	.open = sx_open,
+	.close = gs_close,
+	.write = gs_write,
+	.put_char = gs_put_char,
+	.flush_chars = gs_flush_chars,
+	.write_room = gs_write_room,
+	.chars_in_buffer = gs_chars_in_buffer,
+	.flush_buffer = gs_flush_buffer,
+	.ioctl = sx_ioctl,
+	.throttle = sx_throttle,
+	.unthrottle = sx_unthrottle,
+	.set_termios = gs_set_termios,
+	.stop = gs_stop,
+	.start = gs_start,
+	.hangup = gs_hangup,
+	.tiocmget = sx_tiocmget,
+	.tiocmset = sx_tiocmset,
+};
+
+static const struct tty_port_operations sx_port_ops = {
+	.carrier_raised = sx_carrier_raised,
+};
+
+static int sx_init_drivers(void)
+{
+	int error;
+
+	func_enter();
+
+	sx_driver = alloc_tty_driver(sx_nports);
+	if (!sx_driver)
+		return 1;
+	sx_driver->owner = THIS_MODULE;
+	sx_driver->driver_name = "specialix_sx";
+	sx_driver->name = "ttyX";
+	sx_driver->major = SX_NORMAL_MAJOR;
+	sx_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	sx_driver->subtype = SERIAL_TYPE_NORMAL;
+	sx_driver->init_termios = tty_std_termios;
+	sx_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	sx_driver->init_termios.c_ispeed = 9600;
+	sx_driver->init_termios.c_ospeed = 9600;
+	sx_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(sx_driver, &sx_ops);
+
+	if ((error = tty_register_driver(sx_driver))) {
+		put_tty_driver(sx_driver);
+		printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n",
+			error);
+		return 1;
+	}
+	func_exit();
+	return 0;
+}
+
+static int sx_init_portstructs(int nboards, int nports)
+{
+	struct sx_board *board;
+	struct sx_port *port;
+	int i, j;
+	int addr, chans;
+	int portno;
+
+	func_enter();
+
+	/* Many drivers statically allocate the maximum number of ports
+	   There is no reason not to allocate them dynamically.
+	   Is there? -- REW */
+	sx_ports = kcalloc(nports, sizeof(struct sx_port), GFP_KERNEL);
+	if (!sx_ports)
+		return -ENOMEM;
+
+	port = sx_ports;
+	for (i = 0; i < nboards; i++) {
+		board = &boards[i];
+		board->ports = port;
+		for (j = 0; j < boards[i].nports; j++) {
+			sx_dprintk(SX_DEBUG_INIT, "initing port %d\n", j);
+			tty_port_init(&port->gs.port);
+			port->gs.port.ops = &sx_port_ops;
+			port->gs.magic = SX_MAGIC;
+			port->gs.close_delay = HZ / 2;
+			port->gs.closing_wait = 30 * HZ;
+			port->board = board;
+			port->gs.rd = &sx_real_driver;
+#ifdef NEW_WRITE_LOCKING
+			port->gs.port_write_mutex = MUTEX;
+#endif
+			spin_lock_init(&port->gs.driver_lock);
+			/*
+			 * Initializing wait queue
+			 */
+			port++;
+		}
+	}
+
+	port = sx_ports;
+	portno = 0;
+	for (i = 0; i < nboards; i++) {
+		board = &boards[i];
+		board->port_base = portno;
+		/* Possibly the configuration was rejected. */
+		sx_dprintk(SX_DEBUG_PROBE, "Board has %d channels\n",
+				board->nports);
+		if (board->nports <= 0)
+			continue;
+		/* XXX byteorder ?? */
+		for (addr = 0x80; addr != 0;
+				addr = read_sx_word(board, addr) & 0x7fff) {
+			chans = sx_read_module_byte(board, addr, mc_type);
+			sx_dprintk(SX_DEBUG_PROBE, "Module at %x: %d "
+					"channels\n", addr, chans);
+			sx_dprintk(SX_DEBUG_PROBE, "Port at");
+			for (j = 0; j < chans; j++) {
+				/* The "sx-way" is the way it SHOULD be done.
+				   That way in the future, the firmware may for
+				   example pack the structures a bit more
+				   efficient. Neil tells me it isn't going to
+				   happen anytime soon though. */
+				if (IS_SX_BOARD(board))
+					port->ch_base = sx_read_module_word(
+							board, addr + j * 2,
+							mc_chan_pointer);
+				else
+					port->ch_base = addr + 0x100 + 0x300 *j;
+
+				sx_dprintk(SX_DEBUG_PROBE, " %x",
+						port->ch_base);
+				port->line = portno++;
+				port++;
+			}
+			sx_dprintk(SX_DEBUG_PROBE, "\n");
+		}
+		/* This has to be done earlier. */
+		/* board->flags |= SX_BOARD_INITIALIZED; */
+	}
+
+	func_exit();
+	return 0;
+}
+
+static unsigned int sx_find_free_board(void)
+{
+	unsigned int i;
+
+	for (i = 0; i < SX_NBOARDS; i++)
+		if (!(boards[i].flags & SX_BOARD_PRESENT))
+			break;
+
+	return i;
+}
+
+static void __exit sx_release_drivers(void)
+{
+	func_enter();
+	tty_unregister_driver(sx_driver);
+	put_tty_driver(sx_driver);
+	func_exit();
+}
+
+static void __devexit sx_remove_card(struct sx_board *board,
+		struct pci_dev *pdev)
+{
+	if (board->flags & SX_BOARD_INITIALIZED) {
+		/* The board should stop messing with us. (actually I mean the
+		   interrupt) */
+		sx_reset(board);
+		if ((board->irq) && (board->flags & SX_IRQ_ALLOCATED))
+			free_irq(board->irq, board);
+
+		/* It is safe/allowed to del_timer a non-active timer */
+		del_timer(&board->timer);
+		if (pdev) {
+#ifdef CONFIG_PCI
+			iounmap(board->base2);
+			pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2);
+#endif
+		} else {
+			iounmap(board->base);
+			release_region(board->hw_base, board->hw_len);
+		}
+
+		board->flags &= ~(SX_BOARD_INITIALIZED | SX_BOARD_PRESENT);
+	}
+}
+
+#ifdef CONFIG_EISA
+
+static int __devinit sx_eisa_probe(struct device *dev)
+{
+	struct eisa_device *edev = to_eisa_device(dev);
+	struct sx_board *board;
+	unsigned long eisa_slot = edev->base_addr;
+	unsigned int i;
+	int retval = -EIO;
+
+	mutex_lock(&sx_boards_lock);
+	i = sx_find_free_board();
+	if (i == SX_NBOARDS) {
+		mutex_unlock(&sx_boards_lock);
+		goto err;
+	}
+	board = &boards[i];
+	board->flags |= SX_BOARD_PRESENT;
+	mutex_unlock(&sx_boards_lock);
+
+	dev_info(dev, "XIO : Signature found in EISA slot %lu, "
+		 "Product %d Rev %d (REPORT THIS TO LKLM)\n",
+		 eisa_slot >> 12,
+		 inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 2),
+		 inb(eisa_slot + EISA_VENDOR_ID_OFFSET + 3));
+
+	board->eisa_base = eisa_slot;
+	board->flags &= ~SX_BOARD_TYPE;
+	board->flags |= SI_EISA_BOARD;
+
+	board->hw_base = ((inb(eisa_slot + 0xc01) << 8) +
+			  inb(eisa_slot + 0xc00)) << 16;
+	board->hw_len = SI2_EISA_WINDOW_LEN;
+	if (!request_region(board->hw_base, board->hw_len, "sx")) {
+		dev_err(dev, "can't request region\n");
+		goto err_flag;
+	}
+	board->base2 =
+	board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN);
+	if (!board->base) {
+		dev_err(dev, "can't remap memory\n");
+		goto err_reg;
+	}
+
+	sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
+	sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
+	board->irq = inb(eisa_slot + 0xc02) >> 4;
+	sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
+
+	if (!probe_si(board))
+		goto err_unmap;
+
+	dev_set_drvdata(dev, board);
+
+	return 0;
+err_unmap:
+	iounmap(board->base);
+err_reg:
+	release_region(board->hw_base, board->hw_len);
+err_flag:
+	board->flags &= ~SX_BOARD_PRESENT;
+err:
+	return retval;
+}
+
+static int __devexit sx_eisa_remove(struct device *dev)
+{
+	struct sx_board *board = dev_get_drvdata(dev);
+
+	sx_remove_card(board, NULL);
+
+	return 0;
+}
+
+static struct eisa_device_id sx_eisa_tbl[] = {
+	{ "SLX" },
+	{ "" }
+};
+
+MODULE_DEVICE_TABLE(eisa, sx_eisa_tbl);
+
+static struct eisa_driver sx_eisadriver = {
+	.id_table = sx_eisa_tbl,
+	.driver = {
+		.name = "sx",
+		.probe = sx_eisa_probe,
+		.remove = __devexit_p(sx_eisa_remove),
+	}
+};
+
+#endif
+
+#ifdef CONFIG_PCI
+ /******************************************************** 
+ * Setting bit 17 in the CNTRL register of the PLX 9050  * 
+ * chip forces a retry on writes while a read is pending.*
+ * This is to prevent the card locking up on Intel Xeon  *
+ * multiprocessor systems with the NX chipset.    -- NV  *
+ ********************************************************/
+
+/* Newer cards are produced with this bit set from the configuration
+   EEprom.  As the bit is read/write for the CPU, we can fix it here,
+   if we detect that it isn't set correctly. -- REW */
+
+static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board)
+{
+	unsigned int hwbase;
+	void __iomem *rebase;
+	unsigned int t;
+
+#define CNTRL_REG_OFFSET	0x50
+#define CNTRL_REG_GOODVALUE	0x18260000
+
+	pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
+	hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
+	rebase = ioremap_nocache(hwbase, 0x80);
+	t = readl(rebase + CNTRL_REG_OFFSET);
+	if (t != CNTRL_REG_GOODVALUE) {
+		printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
+			"%08x\n", t, CNTRL_REG_GOODVALUE);
+		writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
+	}
+	iounmap(rebase);
+}
+#endif
+
+static int __devinit sx_pci_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+#ifdef CONFIG_PCI
+	struct sx_board *board;
+	unsigned int i, reg;
+	int retval = -EIO;
+
+	mutex_lock(&sx_boards_lock);
+	i = sx_find_free_board();
+	if (i == SX_NBOARDS) {
+		mutex_unlock(&sx_boards_lock);
+		goto err;
+	}
+	board = &boards[i];
+	board->flags |= SX_BOARD_PRESENT;
+	mutex_unlock(&sx_boards_lock);
+
+	retval = pci_enable_device(pdev);
+	if (retval)
+		goto err_flag;
+
+	board->flags &= ~SX_BOARD_TYPE;
+	board->flags |= (pdev->subsystem_vendor == 0x200) ? SX_PCI_BOARD :
+		SX_CFPCI_BOARD;
+
+	/* CF boards use base address 3.... */
+	reg = IS_CF_BOARD(board) ? 3 : 2;
+	retval = pci_request_region(pdev, reg, "sx");
+	if (retval) {
+		dev_err(&pdev->dev, "can't request region\n");
+		goto err_flag;
+	}
+	board->hw_base = pci_resource_start(pdev, reg);
+	board->base2 =
+	board->base = ioremap_nocache(board->hw_base, WINDOW_LEN(board));
+	if (!board->base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err_reg;
+	}
+
+	/* Most of the stuff on the CF board is offset by 0x18000 ....  */
+	if (IS_CF_BOARD(board))
+		board->base += 0x18000;
+
+	board->irq = pdev->irq;
+
+	dev_info(&pdev->dev, "Got a specialix card: %p(%d) %x.\n", board->base,
+		 board->irq, board->flags);
+
+	if (!probe_sx(board)) {
+		retval = -EIO;
+		goto err_unmap;
+	}
+
+	fix_sx_pci(pdev, board);
+
+	pci_set_drvdata(pdev, board);
+
+	return 0;
+err_unmap:
+	iounmap(board->base2);
+err_reg:
+	pci_release_region(pdev, reg);
+err_flag:
+	board->flags &= ~SX_BOARD_PRESENT;
+err:
+	return retval;
+#else
+	return -ENODEV;
+#endif
+}
+
+static void __devexit sx_pci_remove(struct pci_dev *pdev)
+{
+	struct sx_board *board = pci_get_drvdata(pdev);
+
+	sx_remove_card(board, pdev);
+}
+
+/* Specialix has a whole bunch of cards with 0x2000 as the device ID. They say
+   its because the standard requires it. So check for SUBVENDOR_ID. */
+static struct pci_device_id sx_pci_tbl[] = {
+	{ PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+		.subvendor = PCI_ANY_ID, .subdevice = 0x0200 },
+	{ PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
+		.subvendor = PCI_ANY_ID, .subdevice = 0x0300 },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
+
+static struct pci_driver sx_pcidriver = {
+	.name = "sx",
+	.id_table = sx_pci_tbl,
+	.probe = sx_pci_probe,
+	.remove = __devexit_p(sx_pci_remove)
+};
+
+static int __init sx_init(void)
+{
+#ifdef CONFIG_EISA
+	int retval1;
+#endif
+#ifdef CONFIG_ISA
+	struct sx_board *board;
+	unsigned int i;
+#endif
+	unsigned int found = 0;
+	int retval;
+
+	func_enter();
+	sx_dprintk(SX_DEBUG_INIT, "Initing sx module... (sx_debug=%d)\n",
+			sx_debug);
+	if (abs((long)(&sx_debug) - sx_debug) < 0x10000) {
+		printk(KERN_WARNING "sx: sx_debug is an address, instead of a "
+				"value. Assuming -1.\n(%p)\n", &sx_debug);
+		sx_debug = -1;
+	}
+
+	if (misc_register(&sx_fw_device) < 0) {
+		printk(KERN_ERR "SX: Unable to register firmware loader "
+				"driver.\n");
+		return -EIO;
+	}
+#ifdef CONFIG_ISA
+	for (i = 0; i < NR_SX_ADDRS; i++) {
+		board = &boards[found];
+		board->hw_base = sx_probe_addrs[i];
+		board->hw_len = SX_WINDOW_LEN;
+		if (!request_region(board->hw_base, board->hw_len, "sx"))
+			continue;
+		board->base2 =
+		board->base = ioremap_nocache(board->hw_base, board->hw_len);
+		if (!board->base)
+			goto err_sx_reg;
+		board->flags &= ~SX_BOARD_TYPE;
+		board->flags |= SX_ISA_BOARD;
+		board->irq = sx_irqmask ? -1 : 0;
+
+		if (probe_sx(board)) {
+			board->flags |= SX_BOARD_PRESENT;
+			found++;
+		} else {
+			iounmap(board->base);
+err_sx_reg:
+			release_region(board->hw_base, board->hw_len);
+		}
+	}
+
+	for (i = 0; i < NR_SI_ADDRS; i++) {
+		board = &boards[found];
+		board->hw_base = si_probe_addrs[i];
+		board->hw_len = SI2_ISA_WINDOW_LEN;
+		if (!request_region(board->hw_base, board->hw_len, "sx"))
+			continue;
+		board->base2 =
+		board->base = ioremap_nocache(board->hw_base, board->hw_len);
+		if (!board->base)
+			goto err_si_reg;
+		board->flags &= ~SX_BOARD_TYPE;
+		board->flags |= SI_ISA_BOARD;
+		board->irq = sx_irqmask ? -1 : 0;
+
+		if (probe_si(board)) {
+			board->flags |= SX_BOARD_PRESENT;
+			found++;
+		} else {
+			iounmap(board->base);
+err_si_reg:
+			release_region(board->hw_base, board->hw_len);
+		}
+	}
+	for (i = 0; i < NR_SI1_ADDRS; i++) {
+		board = &boards[found];
+		board->hw_base = si1_probe_addrs[i];
+		board->hw_len = SI1_ISA_WINDOW_LEN;
+		if (!request_region(board->hw_base, board->hw_len, "sx"))
+			continue;
+		board->base2 =
+		board->base = ioremap_nocache(board->hw_base, board->hw_len);
+		if (!board->base)
+			goto err_si1_reg;
+		board->flags &= ~SX_BOARD_TYPE;
+		board->flags |= SI1_ISA_BOARD;
+		board->irq = sx_irqmask ? -1 : 0;
+
+		if (probe_si(board)) {
+			board->flags |= SX_BOARD_PRESENT;
+			found++;
+		} else {
+			iounmap(board->base);
+err_si1_reg:
+			release_region(board->hw_base, board->hw_len);
+		}
+	}
+#endif
+#ifdef CONFIG_EISA
+	retval1 = eisa_driver_register(&sx_eisadriver);
+#endif
+	retval = pci_register_driver(&sx_pcidriver);
+
+	if (found) {
+		printk(KERN_INFO "sx: total of %d boards detected.\n", found);
+		retval = 0;
+	} else if (retval) {
+#ifdef CONFIG_EISA
+		retval = retval1;
+		if (retval1)
+#endif
+			misc_deregister(&sx_fw_device);
+	}
+
+	func_exit();
+	return retval;
+}
+
+static void __exit sx_exit(void)
+{
+	int i;
+
+	func_enter();
+#ifdef CONFIG_EISA
+	eisa_driver_unregister(&sx_eisadriver);
+#endif
+	pci_unregister_driver(&sx_pcidriver);
+
+	for (i = 0; i < SX_NBOARDS; i++)
+		sx_remove_card(&boards[i], NULL);
+
+	if (misc_deregister(&sx_fw_device) < 0) {
+		printk(KERN_INFO "sx: couldn't deregister firmware loader "
+				"device\n");
+	}
+	sx_dprintk(SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n",
+			sx_initialized);
+	if (sx_initialized)
+		sx_release_drivers();
+
+	kfree(sx_ports);
+	func_exit();
+}
+
+module_init(sx_init);
+module_exit(sx_exit);
diff --git a/drivers/staging/generic_serial/sx.h b/drivers/staging/generic_serial/sx.h
new file mode 100644
index 0000000..87c2def
--- /dev/null
+++ b/drivers/staging/generic_serial/sx.h
@@ -0,0 +1,201 @@
+
+/*
+ *  sx.h
+ *
+ *  Copyright (C) 1998/1999 R.E.Wolff@BitWizard.nl
+ *
+ *  SX serial driver.
+ *  -- Supports SI, XIO and SX host cards. 
+ *  -- Supports TAs, MTAs and SXDCs.
+ *
+ *  Version 1.3 -- March, 1999. 
+ * 
+ */
+
+#define SX_NBOARDS        4
+#define SX_PORTSPERBOARD 32
+#define SX_NPORTS        (SX_NBOARDS * SX_PORTSPERBOARD)
+
+#ifdef __KERNEL__
+
+#define SX_MAGIC 0x12345678
+
+struct sx_port {
+  struct gs_port          gs;
+  struct wait_queue       *shutdown_wait;
+  int                     ch_base;
+  int                     c_dcd;
+  struct sx_board         *board;
+  int                     line;
+  unsigned long           locks;
+};
+
+struct sx_board {
+  int magic;
+  void __iomem *base;
+  void __iomem *base2;
+  unsigned long hw_base;
+  resource_size_t hw_len;
+  int eisa_base;
+  int port_base; /* Number of the first port */
+  struct sx_port *ports;
+  int nports;
+  int flags;
+  int irq;
+  int poll;
+  int ta_type;
+  struct timer_list       timer;
+  unsigned long           locks;
+};
+
+struct vpd_prom {
+  unsigned short id;
+  char hwrev;
+  char hwass;
+  int uniqid;
+  char myear;
+  char mweek;
+  char hw_feature[5];
+  char oem_id;
+  char identifier[16];
+};
+
+#ifndef MOD_RS232DB25MALE
+#define MOD_RS232DB25MALE 0x0a
+#endif
+
+#define SI_ISA_BOARD         0x00000001
+#define SX_ISA_BOARD         0x00000002
+#define SX_PCI_BOARD         0x00000004
+#define SX_CFPCI_BOARD       0x00000008
+#define SX_CFISA_BOARD       0x00000010
+#define SI_EISA_BOARD        0x00000020
+#define SI1_ISA_BOARD        0x00000040
+
+#define SX_BOARD_PRESENT     0x00001000
+#define SX_BOARD_INITIALIZED 0x00002000
+#define SX_IRQ_ALLOCATED     0x00004000
+
+#define SX_BOARD_TYPE        0x000000ff
+
+#define IS_SX_BOARD(board) (board->flags & (SX_PCI_BOARD | SX_CFPCI_BOARD | \
+                                            SX_ISA_BOARD | SX_CFISA_BOARD))
+
+#define IS_SI_BOARD(board) (board->flags & SI_ISA_BOARD)
+#define IS_SI1_BOARD(board) (board->flags & SI1_ISA_BOARD)
+
+#define IS_EISA_BOARD(board) (board->flags & SI_EISA_BOARD)
+
+#define IS_CF_BOARD(board) (board->flags & (SX_CFISA_BOARD | SX_CFPCI_BOARD))
+
+/* The SI processor clock is required to calculate the cc_int_count register
+   value for the SI cards. */
+#define SI_PROCESSOR_CLOCK 25000000
+
+
+/* port flags */
+/* Make sure these don't clash with gs flags or async flags */
+#define SX_RX_THROTTLE        0x0000001
+
+
+
+#define SX_PORT_TRANSMIT_LOCK  0
+#define SX_BOARD_INTR_LOCK     0
+
+
+
+/* Debug flags. Add these together to get more debug info. */
+
+#define SX_DEBUG_OPEN          0x00000001
+#define SX_DEBUG_SETTING       0x00000002
+#define SX_DEBUG_FLOW          0x00000004
+#define SX_DEBUG_MODEMSIGNALS  0x00000008
+#define SX_DEBUG_TERMIOS       0x00000010
+#define SX_DEBUG_TRANSMIT      0x00000020
+#define SX_DEBUG_RECEIVE       0x00000040
+#define SX_DEBUG_INTERRUPTS    0x00000080
+#define SX_DEBUG_PROBE         0x00000100
+#define SX_DEBUG_INIT          0x00000200
+#define SX_DEBUG_CLEANUP       0x00000400
+#define SX_DEBUG_CLOSE         0x00000800
+#define SX_DEBUG_FIRMWARE      0x00001000
+#define SX_DEBUG_MEMTEST       0x00002000
+
+#define SX_DEBUG_ALL           0xffffffff
+
+
+#define O_OTHER(tty)    \
+      ((O_OLCUC(tty))  ||\
+      (O_ONLCR(tty))   ||\
+      (O_OCRNL(tty))   ||\
+      (O_ONOCR(tty))   ||\
+      (O_ONLRET(tty))  ||\
+      (O_OFILL(tty))   ||\
+      (O_OFDEL(tty))   ||\
+      (O_NLDLY(tty))   ||\
+      (O_CRDLY(tty))   ||\
+      (O_TABDLY(tty))  ||\
+      (O_BSDLY(tty))   ||\
+      (O_VTDLY(tty))   ||\
+      (O_FFDLY(tty)))
+
+/* Same for input. */
+#define I_OTHER(tty)    \
+      ((I_INLCR(tty))  ||\
+      (I_IGNCR(tty))   ||\
+      (I_ICRNL(tty))   ||\
+      (I_IUCLC(tty))   ||\
+      (L_ISIG(tty)))
+
+#define MOD_TA   (        TA>>4)
+#define MOD_MTA  (MTA_CD1400>>4)
+#define MOD_SXDC (      SXDC>>4)
+
+
+/* We copy the download code over to the card in chunks of ... bytes */
+#define SX_CHUNK_SIZE 128
+
+#endif /* __KERNEL__ */
+
+
+
+/* Specialix document 6210046-11 page 3 */
+#define SPX(X) (('S'<<24) | ('P' << 16) | (X))
+
+/* Specialix-Linux specific IOCTLS. */
+#define SPXL(X) (SPX(('L' << 8) | (X)))
+
+
+#define SXIO_SET_BOARD      SPXL(0x01)
+#define SXIO_GET_TYPE       SPXL(0x02)
+#define SXIO_DOWNLOAD       SPXL(0x03)
+#define SXIO_INIT           SPXL(0x04)
+#define SXIO_SETDEBUG       SPXL(0x05)
+#define SXIO_GETDEBUG       SPXL(0x06)
+#define SXIO_DO_RAMTEST     SPXL(0x07)
+#define SXIO_SETGSDEBUG     SPXL(0x08)
+#define SXIO_GETGSDEBUG     SPXL(0x09)
+#define SXIO_GETNPORTS      SPXL(0x0a)
+
+
+#ifndef SXCTL_MISC_MINOR 
+/* Allow others to gather this into "major.h" or something like that */
+#define SXCTL_MISC_MINOR    167
+#endif
+
+#ifndef SX_NORMAL_MAJOR
+/* This allows overriding on the compiler commandline, or in a "major.h" 
+   include or something like that */
+#define SX_NORMAL_MAJOR  32
+#define SX_CALLOUT_MAJOR 33
+#endif
+
+
+#define SX_TYPE_SX          0x01
+#define SX_TYPE_SI          0x02
+#define SX_TYPE_CF          0x03
+
+
+#define WINDOW_LEN(board) (IS_CF_BOARD(board)?0x20000:SX_WINDOW_LEN)
+/*                         Need a #define for ^^^^^^^ !!! */
+
diff --git a/drivers/staging/generic_serial/sxboards.h b/drivers/staging/generic_serial/sxboards.h
new file mode 100644
index 0000000..427927d
--- /dev/null
+++ b/drivers/staging/generic_serial/sxboards.h
@@ -0,0 +1,206 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	SX/SI/XIO Board Hardware Definitions	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	16th March 1998				*/
+/*									*/
+/*	Version		:	3.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1998	*/
+/*									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the SX/SI/XIO board hardware	*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+3.0.0	16/03/98 NPV	Creation.
+
+*/
+
+#ifndef	_sxboards_h				/* If SXBOARDS.H not already defined */
+#define	_sxboards_h    1
+
+/*****************************************************************************
+*******************************                 ******************************
+*******************************   Board Types   ******************************
+*******************************                 ******************************
+*****************************************************************************/
+
+/* BUS types... */
+#define		BUS_ISA		0
+#define		BUS_MCA		1
+#define		BUS_EISA	2
+#define		BUS_PCI		3
+
+/* Board phases... */
+#define		SI1_Z280	1
+#define		SI2_Z280	2
+#define		SI3_T225	3
+
+/* Board types... */
+#define		CARD_TYPE(bus,phase)	(bus<<4|phase)
+#define		CARD_BUS(type)		((type>>4)&0xF)
+#define		CARD_PHASE(type)	(type&0xF)
+
+#define		TYPE_SI1_ISA		CARD_TYPE(BUS_ISA,SI1_Z280)
+#define		TYPE_SI2_ISA		CARD_TYPE(BUS_ISA,SI2_Z280)
+#define		TYPE_SI2_EISA		CARD_TYPE(BUS_EISA,SI2_Z280)
+#define		TYPE_SI2_PCI		CARD_TYPE(BUS_PCI,SI2_Z280)
+
+#define		TYPE_SX_ISA		CARD_TYPE(BUS_ISA,SI3_T225)
+#define		TYPE_SX_PCI		CARD_TYPE(BUS_PCI,SI3_T225)
+/*****************************************************************************
+******************************                  ******************************
+******************************   Phase 1 Z280   ******************************
+******************************                  ******************************
+*****************************************************************************/
+
+/* ISA board details... */
+#define		SI1_ISA_WINDOW_LEN	0x10000		/* 64 Kbyte shared memory window */
+//#define 	SI1_ISA_MEMORY_LEN	0x8000		/* Usable memory  - unused define*/
+//#define		SI1_ISA_ADDR_LOW	0x0A0000	/* Lowest address = 640 Kbyte */
+//#define		SI1_ISA_ADDR_HIGH	0xFF8000	/* Highest address = 16Mbyte - 32Kbyte */
+//#define		SI2_ISA_ADDR_STEP	SI2_ISA_WINDOW_LEN/* ISA board address step */
+//#define		SI2_ISA_IRQ_MASK	0x9800		/* IRQs 15,12,11 */
+
+/* ISA board, register definitions... */
+//#define		SI2_ISA_ID_BASE		0x7FF8			/* READ:  Board ID string */
+#define		SI1_ISA_RESET		0x8000		/* WRITE: Host Reset */
+#define		SI1_ISA_RESET_CLEAR	0xc000		/* WRITE: Host Reset clear*/
+#define		SI1_ISA_WAIT	        0x9000		/* WRITE: Host wait */
+#define		SI1_ISA_WAIT_CLEAR	0xd000		/* WRITE: Host wait clear */
+#define		SI1_ISA_INTCL        	0xa000		/* WRITE: Host Reset */
+#define		SI1_ISA_INTCL_CLEAR	0xe000		/* WRITE: Host Reset */
+
+
+/*****************************************************************************
+******************************                  ******************************
+******************************   Phase 2 Z280   ******************************
+******************************                  ******************************
+*****************************************************************************/
+
+/* ISA board details... */
+#define		SI2_ISA_WINDOW_LEN	0x8000		/* 32 Kbyte shared memory window */
+#define 	SI2_ISA_MEMORY_LEN	0x7FF8		/* Usable memory */
+#define		SI2_ISA_ADDR_LOW	0x0A0000	/* Lowest address = 640 Kbyte */
+#define		SI2_ISA_ADDR_HIGH	0xFF8000	/* Highest address = 16Mbyte - 32Kbyte */
+#define		SI2_ISA_ADDR_STEP	SI2_ISA_WINDOW_LEN/* ISA board address step */
+#define		SI2_ISA_IRQ_MASK	0x9800		/* IRQs 15,12,11 */
+
+/* ISA board, register definitions... */
+#define		SI2_ISA_ID_BASE		0x7FF8			/* READ:  Board ID string */
+#define		SI2_ISA_RESET		SI2_ISA_ID_BASE		/* WRITE: Host Reset */
+#define		SI2_ISA_IRQ11		(SI2_ISA_ID_BASE+1)	/* WRITE: Set IRQ11 */
+#define		SI2_ISA_IRQ12		(SI2_ISA_ID_BASE+2)	/* WRITE: Set IRQ12 */
+#define		SI2_ISA_IRQ15		(SI2_ISA_ID_BASE+3)	/* WRITE: Set IRQ15 */
+#define		SI2_ISA_IRQSET		(SI2_ISA_ID_BASE+4)	/* WRITE: Set Host Interrupt */
+#define		SI2_ISA_INTCLEAR	(SI2_ISA_ID_BASE+5)	/* WRITE: Enable Host Interrupt */
+
+#define		SI2_ISA_IRQ11_SET	0x10
+#define		SI2_ISA_IRQ11_CLEAR	0x00
+#define		SI2_ISA_IRQ12_SET	0x10
+#define		SI2_ISA_IRQ12_CLEAR	0x00
+#define		SI2_ISA_IRQ15_SET	0x10
+#define		SI2_ISA_IRQ15_CLEAR	0x00
+#define		SI2_ISA_INTCLEAR_SET	0x10
+#define		SI2_ISA_INTCLEAR_CLEAR	0x00
+#define		SI2_ISA_IRQSET_CLEAR	0x10
+#define		SI2_ISA_IRQSET_SET	0x00
+#define		SI2_ISA_RESET_SET	0x00
+#define		SI2_ISA_RESET_CLEAR	0x10
+
+/* PCI board details... */
+#define		SI2_PCI_WINDOW_LEN	0x100000	/* 1 Mbyte memory window */
+
+/* PCI board register definitions... */
+#define		SI2_PCI_SET_IRQ		0x40001		/* Set Host Interrupt  */
+#define		SI2_PCI_RESET		0xC0001		/* Host Reset */
+
+/*****************************************************************************
+******************************                  ******************************
+******************************   Phase 3 T225   ******************************
+******************************                  ******************************
+*****************************************************************************/
+
+/* General board details... */
+#define		SX_WINDOW_LEN		64*1024		/* 64 Kbyte memory window */
+
+/* ISA board details... */
+#define		SX_ISA_ADDR_LOW		0x0A0000	/* Lowest address = 640 Kbyte */
+#define		SX_ISA_ADDR_HIGH	0xFF8000	/* Highest address = 16Mbyte - 32Kbyte */
+#define		SX_ISA_ADDR_STEP	SX_WINDOW_LEN	/* ISA board address step */
+#define		SX_ISA_IRQ_MASK		0x9E00		/* IRQs 15,12,11,10,9 */
+
+/* Hardware register definitions... */
+#define		SX_EVENT_STATUS		0x7800		/* READ:  T225 Event Status */
+#define		SX_EVENT_STROBE		0x7800		/* WRITE: T225 Event Strobe */
+#define		SX_EVENT_ENABLE		0x7880		/* WRITE: T225 Event Enable */
+#define		SX_VPD_ROM		0x7C00		/* READ:  Vital Product Data ROM */
+#define		SX_CONFIG		0x7C00		/* WRITE: Host Configuration Register */
+#define		SX_IRQ_STATUS		0x7C80		/* READ:  Host Interrupt Status */
+#define		SX_SET_IRQ		0x7C80		/* WRITE: Set Host Interrupt */
+#define		SX_RESET_STATUS		0x7D00		/* READ:  Host Reset Status */
+#define		SX_RESET		0x7D00		/* WRITE: Host Reset */
+#define		SX_RESET_IRQ		0x7D80		/* WRITE: Reset Host Interrupt */
+
+/* SX_VPD_ROM definitions... */
+#define		SX_VPD_SLX_ID1		0x00
+#define		SX_VPD_SLX_ID2		0x01
+#define		SX_VPD_HW_REV		0x02
+#define		SX_VPD_HW_ASSEM		0x03
+#define		SX_VPD_UNIQUEID4	0x04
+#define		SX_VPD_UNIQUEID3	0x05
+#define		SX_VPD_UNIQUEID2	0x06
+#define		SX_VPD_UNIQUEID1	0x07
+#define		SX_VPD_MANU_YEAR	0x08
+#define		SX_VPD_MANU_WEEK	0x09
+#define		SX_VPD_IDENT		0x10
+#define		SX_VPD_IDENT_STRING	"JET HOST BY KEV#"
+
+/* SX unique identifiers... */
+#define		SX_UNIQUEID_MASK	0xF0
+#define		SX_ISA_UNIQUEID1	0x20
+#define		SX_PCI_UNIQUEID1	0x50
+
+/* SX_CONFIG definitions... */
+#define		SX_CONF_BUSEN		0x02		/* Enable T225 memory and I/O */
+#define		SX_CONF_HOSTIRQ		0x04		/* Enable board to host interrupt */
+
+/* SX bootstrap... */
+#define		SX_BOOTSTRAP		"\x28\x20\x21\x02\x60\x0a"
+#define		SX_BOOTSTRAP_SIZE	6
+#define		SX_BOOTSTRAP_ADDR	(0x8000-SX_BOOTSTRAP_SIZE)
+
+/*****************************************************************************
+**********************************          **********************************
+**********************************   EISA   **********************************
+**********************************          **********************************
+*****************************************************************************/
+
+#define		SI2_EISA_OFF	 	0x42
+#define		SI2_EISA_VAL	 	0x01
+#define		SI2_EISA_WINDOW_LEN     0x10000
+
+/*****************************************************************************
+***********************************         **********************************
+***********************************   PCI   **********************************
+***********************************         **********************************
+*****************************************************************************/
+
+/* General definitions... */
+
+#define		SPX_VENDOR_ID		0x11CB		/* Assigned by the PCI SIG */
+#define		SPX_DEVICE_ID		0x4000		/* SI/XIO boards */
+#define		SPX_PLXDEVICE_ID	0x2000		/* SX boards */
+
+#define		SPX_SUB_VENDOR_ID	SPX_VENDOR_ID	/* Same as vendor id */
+#define		SI2_SUB_SYS_ID		0x400		/* Phase 2 (Z280) board */
+#define		SX_SUB_SYS_ID		0x200		/* Phase 3 (t225) board */
+
+#endif						/*_sxboards_h */
+
+/* End of SXBOARDS.H */
diff --git a/drivers/staging/generic_serial/sxwindow.h b/drivers/staging/generic_serial/sxwindow.h
new file mode 100644
index 0000000..cf01b66
--- /dev/null
+++ b/drivers/staging/generic_serial/sxwindow.h
@@ -0,0 +1,393 @@
+/************************************************************************/
+/*									*/
+/*	Title		:	SX Shared Memory Window Structure	*/
+/*									*/
+/*	Author		:	N.P.Vassallo				*/
+/*									*/
+/*	Creation	:	16th March 1998				*/
+/*									*/
+/*	Version		:	3.0.0					*/
+/*									*/
+/*	Copyright	:	(c) Specialix International Ltd. 1998	*/
+/*									*/
+/*	Description	:	Prototypes, structures and definitions	*/
+/*				describing the SX/SI/XIO cards shared	*/
+/*				memory window structure:		*/
+/*					SXCARD				*/
+/*					SXMODULE			*/
+/*					SXCHANNEL			*/
+/*									*/
+/************************************************************************/
+
+/* History...
+
+3.0.0	16/03/98 NPV	Creation. (based on STRUCT.H)
+
+*/
+
+#ifndef	_sxwindow_h				/* If SXWINDOW.H not already defined */
+#define	_sxwindow_h    1
+
+/*****************************************************************************
+***************************                        ***************************
+***************************   Common Definitions   ***************************
+***************************                        ***************************
+*****************************************************************************/
+
+typedef	struct	_SXCARD		*PSXCARD;	/* SXCARD structure pointer */
+typedef	struct	_SXMODULE	*PMOD;		/* SXMODULE structure pointer */
+typedef	struct	_SXCHANNEL	*PCHAN;		/* SXCHANNEL structure pointer */
+
+/*****************************************************************************
+*********************************            *********************************
+*********************************   SXCARD   *********************************
+*********************************            *********************************
+*****************************************************************************/
+
+typedef	struct	_SXCARD
+{
+	BYTE	cc_init_status;			/* 0x00 Initialisation status */
+	BYTE	cc_mem_size;			/* 0x01 Size of memory on card */
+	WORD	cc_int_count;			/* 0x02 Interrupt count */
+	WORD	cc_revision;			/* 0x04 Download code revision */
+	BYTE	cc_isr_count;			/* 0x06 Count when ISR is run */
+	BYTE	cc_main_count;			/* 0x07 Count when main loop is run */
+	WORD	cc_int_pending;			/* 0x08 Interrupt pending */
+	WORD	cc_poll_count;			/* 0x0A Count when poll is run */
+	BYTE	cc_int_set_count;		/* 0x0C Count when host interrupt is set */
+	BYTE	cc_rfu[0x80 - 0x0D];		/* 0x0D Pad structure to 128 bytes (0x80) */
+
+} SXCARD;
+
+/* SXCARD.cc_init_status definitions... */
+#define 	ADAPTERS_FOUND		(BYTE)0x01
+#define 	NO_ADAPTERS_FOUND	(BYTE)0xFF
+
+/* SXCARD.cc_mem_size definitions... */
+#define 	SX_MEMORY_SIZE		(BYTE)0x40
+
+/* SXCARD.cc_int_count definitions... */
+#define 	INT_COUNT_DEFAULT	100	/* Hz */
+
+/*****************************************************************************
+********************************              ********************************
+********************************   SXMODULE   ********************************
+********************************              ********************************
+*****************************************************************************/
+
+#define	TOP_POINTER(a)		((a)|0x8000)	/* Sets top bit of word */
+#define UNTOP_POINTER(a)	((a)&~0x8000)	/* Clears top bit of word */
+
+typedef	struct	_SXMODULE
+{
+	WORD	mc_next;			/* 0x00 Next module "pointer" (ORed with 0x8000) */
+	BYTE	mc_type;			/* 0x02 Type of TA in terms of number of channels */
+	BYTE	mc_mod_no;			/* 0x03 Module number on SI bus cable (0 closest to card) */
+	BYTE	mc_dtr;				/* 0x04 Private DTR copy (TA only) */
+	BYTE	mc_rfu1;			/* 0x05 Reserved */
+	WORD	mc_uart;			/* 0x06 UART base address for this module */
+	BYTE	mc_chip;			/* 0x08 Chip type / number of ports */
+	BYTE	mc_current_uart;		/* 0x09 Current uart selected for this module */
+#ifdef	DOWNLOAD
+	PCHAN	mc_chan_pointer[8];		/* 0x0A Pointer to each channel structure */
+#else
+	WORD	mc_chan_pointer[8];		/* 0x0A Define as WORD if not compiling into download */
+#endif
+	WORD	mc_rfu2;			/* 0x1A Reserved */
+	BYTE	mc_opens1;			/* 0x1C Number of open ports on first four ports on MTA/SXDC */
+	BYTE	mc_opens2;			/* 0x1D Number of open ports on second four ports on MTA/SXDC */
+	BYTE	mc_mods;			/* 0x1E Types of connector module attached to MTA/SXDC */
+	BYTE	mc_rev1;			/* 0x1F Revision of first CD1400 on MTA/SXDC */
+	BYTE	mc_rev2;			/* 0x20 Revision of second CD1400 on MTA/SXDC */
+	BYTE	mc_mtaasic_rev;			/* 0x21 Revision of MTA ASIC 1..4 -> A, B, C, D */
+	BYTE	mc_rfu3[0x100 - 0x22];		/* 0x22 Pad structure to 256 bytes (0x100) */
+
+} SXMODULE;
+
+/* SXMODULE.mc_type definitions... */
+#define		FOUR_PORTS	(BYTE)4
+#define 	EIGHT_PORTS	(BYTE)8
+
+/* SXMODULE.mc_chip definitions... */
+#define 	CHIP_MASK	0xF0
+#define		TA		(BYTE)0
+#define 	TA4		(TA | FOUR_PORTS)
+#define 	TA8		(TA | EIGHT_PORTS)
+#define		TA4_ASIC	(BYTE)0x0A
+#define		TA8_ASIC	(BYTE)0x0B
+#define 	MTA_CD1400	(BYTE)0x28
+#define 	SXDC		(BYTE)0x48
+
+/* SXMODULE.mc_mods definitions... */
+#define		MOD_RS232DB25	0x00		/* RS232 DB25 (socket/plug) */
+#define		MOD_RS232RJ45	0x01		/* RS232 RJ45 (shielded/opto-isolated) */
+#define		MOD_RESERVED_2	0x02		/* Reserved (RS485) */
+#define		MOD_RS422DB25	0x03		/* RS422 DB25 Socket */
+#define		MOD_RESERVED_4	0x04		/* Reserved */
+#define		MOD_PARALLEL	0x05		/* Parallel */
+#define		MOD_RESERVED_6	0x06		/* Reserved (RS423) */
+#define		MOD_RESERVED_7	0x07		/* Reserved */
+#define		MOD_2_RS232DB25	0x08		/* Rev 2.0 RS232 DB25 (socket/plug) */
+#define		MOD_2_RS232RJ45	0x09		/* Rev 2.0 RS232 RJ45 */
+#define		MOD_RESERVED_A	0x0A		/* Rev 2.0 Reserved */
+#define		MOD_2_RS422DB25	0x0B		/* Rev 2.0 RS422 DB25 */
+#define		MOD_RESERVED_C	0x0C		/* Rev 2.0 Reserved */
+#define		MOD_2_PARALLEL	0x0D		/* Rev 2.0 Parallel */
+#define		MOD_RESERVED_E	0x0E		/* Rev 2.0 Reserved */
+#define		MOD_BLANK	0x0F		/* Blank Panel */
+
+/*****************************************************************************
+********************************               *******************************
+********************************   SXCHANNEL   *******************************
+********************************               *******************************
+*****************************************************************************/
+
+#define		TX_BUFF_OFFSET		0x60	/* Transmit buffer offset in channel structure */
+#define		BUFF_POINTER(a)		(((a)+TX_BUFF_OFFSET)|0x8000)
+#define		UNBUFF_POINTER(a)	(jet_channel*)(((a)&~0x8000)-TX_BUFF_OFFSET) 
+#define 	BUFFER_SIZE		256
+#define 	HIGH_WATER		((BUFFER_SIZE / 4) * 3)
+#define 	LOW_WATER		(BUFFER_SIZE / 4)
+
+typedef	struct	_SXCHANNEL
+{
+	WORD	next_item;			/* 0x00 Offset from window base of next channels hi_txbuf (ORred with 0x8000) */
+	WORD 	addr_uart;			/* 0x02 INTERNAL pointer to uart address. Includes FASTPATH bit */
+	WORD	module;				/* 0x04 Offset from window base of parent SXMODULE structure */
+	BYTE 	type;				/* 0x06 Chip type / number of ports (copy of mc_chip) */
+	BYTE	chan_number;			/* 0x07 Channel number on the TA/MTA/SXDC */
+	WORD	xc_status;			/* 0x08 Flow control and I/O status */
+	BYTE	hi_rxipos;			/* 0x0A Receive buffer input index */
+	BYTE	hi_rxopos;			/* 0x0B Receive buffer output index */
+	BYTE	hi_txopos;			/* 0x0C Transmit buffer output index */
+	BYTE	hi_txipos;			/* 0x0D Transmit buffer input index */
+	BYTE	hi_hstat;			/* 0x0E Command register */
+	BYTE	dtr_bit;			/* 0x0F INTERNAL DTR control byte (TA only) */
+	BYTE	txon;				/* 0x10 INTERNAL copy of hi_txon */
+	BYTE	txoff;				/* 0x11 INTERNAL copy of hi_txoff */
+	BYTE	rxon;				/* 0x12 INTERNAL copy of hi_rxon */
+	BYTE	rxoff;				/* 0x13 INTERNAL copy of hi_rxoff */
+	BYTE	hi_mr1;				/* 0x14 Mode Register 1 (databits,parity,RTS rx flow)*/
+	BYTE	hi_mr2;				/* 0x15 Mode Register 2 (stopbits,local,CTS tx flow)*/
+	BYTE	hi_csr;				/* 0x16 Clock Select Register (baud rate) */
+	BYTE	hi_op;				/* 0x17 Modem Output Signal */
+	BYTE	hi_ip;				/* 0x18 Modem Input Signal */
+	BYTE	hi_state;			/* 0x19 Channel status */
+	BYTE	hi_prtcl;			/* 0x1A Channel protocol (flow control) */
+	BYTE	hi_txon;			/* 0x1B Transmit XON character */
+	BYTE	hi_txoff;			/* 0x1C Transmit XOFF character */
+	BYTE	hi_rxon;			/* 0x1D Receive XON character */
+	BYTE	hi_rxoff;			/* 0x1E Receive XOFF character */
+	BYTE	close_prev;			/* 0x1F INTERNAL channel previously closed flag */
+	BYTE	hi_break;			/* 0x20 Break and error control */
+	BYTE	break_state;			/* 0x21 INTERNAL copy of hi_break */
+	BYTE	hi_mask;			/* 0x22 Mask for received data */
+	BYTE	mask;				/* 0x23 INTERNAL copy of hi_mask */
+	BYTE	mod_type;			/* 0x24 MTA/SXDC hardware module type */
+	BYTE	ccr_state;			/* 0x25 INTERNAL MTA/SXDC state of CCR register */
+	BYTE	ip_mask;			/* 0x26 Input handshake mask */
+	BYTE	hi_parallel;			/* 0x27 Parallel port flag */
+	BYTE	par_error;			/* 0x28 Error code for parallel loopback test */
+	BYTE	any_sent;			/* 0x29 INTERNAL data sent flag */
+	BYTE	asic_txfifo_size;		/* 0x2A INTERNAL SXDC transmit FIFO size */
+	BYTE	rfu1[2];			/* 0x2B Reserved */
+	BYTE	csr;				/* 0x2D INTERNAL copy of hi_csr */
+#ifdef	DOWNLOAD
+	PCHAN	nextp;				/* 0x2E Offset from window base of next channel structure */
+#else
+	WORD	nextp;				/* 0x2E Define as WORD if not compiling into download */
+#endif
+	BYTE	prtcl;				/* 0x30 INTERNAL copy of hi_prtcl */
+	BYTE	mr1;				/* 0x31 INTERNAL copy of hi_mr1 */
+	BYTE	mr2;				/* 0x32 INTERNAL copy of hi_mr2 */
+	BYTE	hi_txbaud;			/* 0x33 Extended transmit baud rate (SXDC only if((hi_csr&0x0F)==0x0F) */
+	BYTE	hi_rxbaud;			/* 0x34 Extended receive baud rate  (SXDC only if((hi_csr&0xF0)==0xF0) */
+	BYTE	txbreak_state;			/* 0x35 INTERNAL MTA/SXDC transmit break state */
+	BYTE	txbaud;				/* 0x36 INTERNAL copy of hi_txbaud */
+	BYTE	rxbaud;				/* 0x37 INTERNAL copy of hi_rxbaud */
+	WORD	err_framing;			/* 0x38 Count of receive framing errors */
+	WORD	err_parity;			/* 0x3A Count of receive parity errors */
+	WORD	err_overrun;			/* 0x3C Count of receive overrun errors */
+	WORD	err_overflow;			/* 0x3E Count of receive buffer overflow errors */
+	BYTE	rfu2[TX_BUFF_OFFSET - 0x40];	/* 0x40 Reserved until hi_txbuf */
+	BYTE	hi_txbuf[BUFFER_SIZE];		/* 0x060 Transmit buffer */
+	BYTE	hi_rxbuf[BUFFER_SIZE];		/* 0x160 Receive buffer */
+	BYTE	rfu3[0x300 - 0x260];		/* 0x260 Reserved until 768 bytes (0x300) */
+
+} SXCHANNEL;
+
+/* SXCHANNEL.addr_uart definitions... */
+#define		FASTPATH	0x1000		/* Set to indicate fast rx/tx processing (TA only) */
+
+/* SXCHANNEL.xc_status definitions... */
+#define		X_TANY		0x0001		/* XON is any character (TA only) */
+#define		X_TION		0x0001		/* Tx interrupts on (MTA only) */
+#define		X_TXEN		0x0002		/* Tx XON/XOFF enabled (TA only) */
+#define		X_RTSEN		0x0002		/* RTS FLOW enabled (MTA only) */
+#define		X_TXRC		0x0004		/* XOFF received (TA only) */
+#define		X_RTSLOW	0x0004		/* RTS dropped (MTA only) */
+#define		X_RXEN		0x0008		/* Rx XON/XOFF enabled */
+#define		X_ANYXO		0x0010		/* XOFF pending/sent or RTS dropped */
+#define		X_RXSE		0x0020		/* Rx XOFF sent */
+#define		X_NPEND		0x0040		/* Rx XON pending or XOFF pending */
+#define		X_FPEND		0x0080		/* Rx XOFF pending */
+#define		C_CRSE		0x0100		/* Carriage return sent (TA only) */
+#define		C_TEMR		0x0100		/* Tx empty requested (MTA only) */
+#define		C_TEMA		0x0200		/* Tx empty acked (MTA only) */
+#define		C_ANYP		0x0200		/* Any protocol bar tx XON/XOFF (TA only) */
+#define		C_EN		0x0400		/* Cooking enabled (on MTA means port is also || */
+#define		C_HIGH		0x0800		/* Buffer previously hit high water */
+#define		C_CTSEN		0x1000		/* CTS automatic flow-control enabled */
+#define		C_DCDEN		0x2000		/* DCD/DTR checking enabled */
+#define		C_BREAK		0x4000		/* Break detected */
+#define		C_RTSEN		0x8000		/* RTS automatic flow control enabled (MTA only) */
+#define		C_PARITY	0x8000		/* Parity checking enabled (TA only) */
+
+/* SXCHANNEL.hi_hstat definitions... */
+#define		HS_IDLE_OPEN	0x00		/* Channel open state */
+#define		HS_LOPEN	0x02		/* Local open command (no modem monitoring) */
+#define		HS_MOPEN	0x04		/* Modem open command (wait for DCD signal) */
+#define		HS_IDLE_MPEND	0x06		/* Waiting for DCD signal state */
+#define		HS_CONFIG	0x08		/* Configuration command */
+#define		HS_CLOSE	0x0A		/* Close command */
+#define		HS_START	0x0C		/* Start transmit break command */
+#define		HS_STOP		0x0E		/* Stop transmit break command */
+#define		HS_IDLE_CLOSED	0x10		/* Closed channel state */
+#define		HS_IDLE_BREAK	0x12		/* Transmit break state */
+#define		HS_FORCE_CLOSED	0x14		/* Force close command */
+#define		HS_RESUME	0x16		/* Clear pending XOFF command */
+#define		HS_WFLUSH	0x18		/* Flush transmit buffer command */
+#define		HS_RFLUSH	0x1A		/* Flush receive buffer command */
+#define		HS_SUSPEND	0x1C		/* Suspend output command (like XOFF received) */
+#define		PARALLEL	0x1E		/* Parallel port loopback test command (Diagnostics Only) */
+#define		ENABLE_RX_INTS	0x20		/* Enable receive interrupts command (Diagnostics Only) */
+#define		ENABLE_TX_INTS	0x22		/* Enable transmit interrupts command (Diagnostics Only) */
+#define		ENABLE_MDM_INTS	0x24		/* Enable modem interrupts command (Diagnostics Only) */
+#define		DISABLE_INTS	0x26		/* Disable interrupts command (Diagnostics Only) */
+
+/* SXCHANNEL.hi_mr1 definitions... */
+#define		MR1_BITS	0x03		/* Data bits mask */
+#define		MR1_5_BITS	0x00		/* 5 data bits */
+#define		MR1_6_BITS	0x01		/* 6 data bits */
+#define		MR1_7_BITS	0x02		/* 7 data bits */
+#define		MR1_8_BITS	0x03		/* 8 data bits */
+#define		MR1_PARITY	0x1C		/* Parity mask */
+#define		MR1_ODD		0x04		/* Odd parity */
+#define		MR1_EVEN	0x00		/* Even parity */
+#define		MR1_WITH	0x00		/* Parity enabled */
+#define		MR1_FORCE	0x08		/* Force parity */
+#define		MR1_NONE	0x10		/* No parity */
+#define		MR1_NOPARITY	MR1_NONE		/* No parity */
+#define		MR1_ODDPARITY	(MR1_WITH|MR1_ODD)	/* Odd parity */
+#define		MR1_EVENPARITY	(MR1_WITH|MR1_EVEN)	/* Even parity */
+#define		MR1_MARKPARITY	(MR1_FORCE|MR1_ODD)	/* Mark parity */
+#define		MR1_SPACEPARITY	(MR1_FORCE|MR1_EVEN)	/* Space parity */
+#define		MR1_RTS_RXFLOW	0x80		/* RTS receive flow control */
+
+/* SXCHANNEL.hi_mr2 definitions... */
+#define		MR2_STOP	0x0F		/* Stop bits mask */
+#define		MR2_1_STOP	0x07		/* 1 stop bit */
+#define		MR2_2_STOP	0x0F		/* 2 stop bits */
+#define		MR2_CTS_TXFLOW	0x10		/* CTS transmit flow control */
+#define		MR2_RTS_TOGGLE	0x20		/* RTS toggle on transmit */
+#define		MR2_NORMAL	0x00		/* Normal mode */
+#define		MR2_AUTO	0x40		/* Auto-echo mode (TA only) */
+#define		MR2_LOCAL	0x80		/* Local echo mode */
+#define		MR2_REMOTE	0xC0		/* Remote echo mode (TA only) */
+
+/* SXCHANNEL.hi_csr definitions... */
+#define		CSR_75		0x0		/*    75 baud */
+#define		CSR_110		0x1		/*   110 baud (TA), 115200 (MTA/SXDC) */
+#define		CSR_38400	0x2		/* 38400 baud */
+#define		CSR_150		0x3		/*   150 baud */
+#define		CSR_300		0x4		/*   300 baud */
+#define		CSR_600		0x5		/*   600 baud */
+#define		CSR_1200	0x6		/*  1200 baud */
+#define		CSR_2000	0x7		/*  2000 baud */
+#define		CSR_2400	0x8		/*  2400 baud */
+#define		CSR_4800	0x9		/*  4800 baud */
+#define		CSR_1800	0xA		/*  1800 baud */
+#define		CSR_9600	0xB		/*  9600 baud */
+#define		CSR_19200	0xC		/* 19200 baud */
+#define		CSR_57600	0xD		/* 57600 baud */
+#define		CSR_EXTBAUD	0xF		/* Extended baud rate (hi_txbaud/hi_rxbaud) */
+
+/* SXCHANNEL.hi_op definitions... */
+#define		OP_RTS		0x01		/* RTS modem output signal */
+#define		OP_DTR		0x02		/* DTR modem output signal */
+
+/* SXCHANNEL.hi_ip definitions... */
+#define		IP_CTS		0x02		/* CTS modem input signal */
+#define		IP_DCD		0x04		/* DCD modem input signal */
+#define		IP_DSR		0x20		/* DTR modem input signal */
+#define		IP_RI		0x40		/* RI modem input signal */
+
+/* SXCHANNEL.hi_state definitions... */
+#define		ST_BREAK	0x01		/* Break received (clear with config) */
+#define		ST_DCD		0x02		/* DCD signal changed state */
+
+/* SXCHANNEL.hi_prtcl definitions... */
+#define		SP_TANY		0x01		/* Transmit XON/XANY (if SP_TXEN enabled) */
+#define		SP_TXEN		0x02		/* Transmit XON/XOFF flow control */
+#define		SP_CEN		0x04		/* Cooking enabled */
+#define		SP_RXEN		0x08		/* Rx XON/XOFF enabled */
+#define		SP_DCEN		0x20		/* DCD / DTR check */
+#define		SP_DTR_RXFLOW	0x40		/* DTR receive flow control */
+#define		SP_PAEN		0x80		/* Parity checking enabled */
+
+/* SXCHANNEL.hi_break definitions... */
+#define		BR_IGN		0x01		/* Ignore any received breaks */
+#define		BR_INT		0x02		/* Interrupt on received break */
+#define		BR_PARMRK	0x04		/* Enable parmrk parity error processing */
+#define		BR_PARIGN	0x08		/* Ignore chars with parity errors */
+#define 	BR_ERRINT	0x80		/* Treat parity/framing/overrun errors as exceptions */
+
+/* SXCHANNEL.par_error definitions.. */
+#define		DIAG_IRQ_RX	0x01		/* Indicate serial receive interrupt (diags only) */
+#define		DIAG_IRQ_TX	0x02		/* Indicate serial transmit interrupt (diags only) */
+#define		DIAG_IRQ_MD	0x04		/* Indicate serial modem interrupt (diags only) */
+
+/* SXCHANNEL.hi_txbaud/hi_rxbaud definitions... (SXDC only) */
+#define		BAUD_75		0x00		/*     75 baud */
+#define		BAUD_115200	0x01		/* 115200 baud */
+#define		BAUD_38400	0x02		/*  38400 baud */
+#define		BAUD_150	0x03		/*    150 baud */
+#define		BAUD_300	0x04		/*    300 baud */
+#define		BAUD_600	0x05		/*    600 baud */
+#define		BAUD_1200	0x06		/*   1200 baud */
+#define		BAUD_2000	0x07		/*   2000 baud */
+#define		BAUD_2400	0x08		/*   2400 baud */
+#define		BAUD_4800	0x09		/*   4800 baud */
+#define		BAUD_1800	0x0A		/*   1800 baud */
+#define		BAUD_9600	0x0B		/*   9600 baud */
+#define		BAUD_19200	0x0C		/*  19200 baud */
+#define		BAUD_57600	0x0D		/*  57600 baud */
+#define		BAUD_230400	0x0E		/* 230400 baud */
+#define		BAUD_460800	0x0F		/* 460800 baud */
+#define		BAUD_921600	0x10		/* 921600 baud */
+#define		BAUD_50		0x11    	/*     50 baud */
+#define		BAUD_110	0x12		/*    110 baud */
+#define		BAUD_134_5	0x13		/*  134.5 baud */
+#define		BAUD_200	0x14		/*    200 baud */
+#define		BAUD_7200	0x15		/*   7200 baud */
+#define		BAUD_56000	0x16		/*  56000 baud */
+#define		BAUD_64000	0x17		/*  64000 baud */
+#define		BAUD_76800	0x18		/*  76800 baud */
+#define		BAUD_128000	0x19		/* 128000 baud */
+#define		BAUD_150000	0x1A		/* 150000 baud */
+#define		BAUD_14400	0x1B		/*  14400 baud */
+#define		BAUD_256000	0x1C		/* 256000 baud */
+#define		BAUD_28800	0x1D		/*  28800 baud */
+
+/* SXCHANNEL.txbreak_state definiions... */
+#define		TXBREAK_OFF	0		/* Not sending break */
+#define		TXBREAK_START	1		/* Begin sending break */
+#define		TXBREAK_START1	2		/* Begin sending break, part 1 */
+#define		TXBREAK_ON	3		/* Sending break */
+#define		TXBREAK_STOP	4		/* Stop sending break */
+#define		TXBREAK_STOP1	5		/* Stop sending break, part 1 */
+
+#endif						/* _sxwindow_h */
+
+/* End of SXWINDOW.H */
+
diff --git a/drivers/staging/generic_serial/vme_scc.c b/drivers/staging/generic_serial/vme_scc.c
new file mode 100644
index 0000000..9683864
--- /dev/null
+++ b/drivers/staging/generic_serial/vme_scc.c
@@ -0,0 +1,1145 @@
+/*
+ * drivers/char/vme_scc.c: MVME147, MVME162, BVME6000 SCC serial ports
+ * implementation.
+ * Copyright 1999 Richard Hirst <richard@sleepie.demon.co.uk>
+ *
+ * Based on atari_SCC.c which was
+ *   Copyright 1994-95 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *   Partially based on PC-Linux serial.c by Linus Torvalds and Theodore Ts'o
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kdev_t.h>
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/mm.h>
+#include <linux/serial.h>
+#include <linux/fcntl.h>
+#include <linux/major.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <asm/setup.h>
+#include <asm/bootinfo.h>
+
+#ifdef CONFIG_MVME147_SCC
+#include <asm/mvme147hw.h>
+#endif
+#ifdef CONFIG_MVME162_SCC
+#include <asm/mvme16xhw.h>
+#endif
+#ifdef CONFIG_BVME6000_SCC
+#include <asm/bvme6000hw.h>
+#endif
+
+#include <linux/generic_serial.h>
+#include "scc.h"
+
+
+#define CHANNEL_A	0
+#define CHANNEL_B	1
+
+#define SCC_MINOR_BASE	64
+
+/* Shadows for all SCC write registers */
+static unsigned char scc_shadow[2][16];
+
+/* Location to access for SCC register access delay */
+static volatile unsigned char *scc_del = NULL;
+
+/* To keep track of STATUS_REG state for detection of Ext/Status int source */
+static unsigned char scc_last_status_reg[2];
+
+/***************************** Prototypes *****************************/
+
+/* Function prototypes */
+static void scc_disable_tx_interrupts(void * ptr);
+static void scc_enable_tx_interrupts(void * ptr);
+static void scc_disable_rx_interrupts(void * ptr);
+static void scc_enable_rx_interrupts(void * ptr);
+static int  scc_carrier_raised(struct tty_port *port);
+static void scc_shutdown_port(void * ptr);
+static int scc_set_real_termios(void  *ptr);
+static void scc_hungup(void  *ptr);
+static void scc_close(void  *ptr);
+static int scc_chars_in_buffer(void * ptr);
+static int scc_open(struct tty_struct * tty, struct file * filp);
+static int scc_ioctl(struct tty_struct * tty,
+                     unsigned int cmd, unsigned long arg);
+static void scc_throttle(struct tty_struct *tty);
+static void scc_unthrottle(struct tty_struct *tty);
+static irqreturn_t scc_tx_int(int irq, void *data);
+static irqreturn_t scc_rx_int(int irq, void *data);
+static irqreturn_t scc_stat_int(int irq, void *data);
+static irqreturn_t scc_spcond_int(int irq, void *data);
+static void scc_setsignals(struct scc_port *port, int dtr, int rts);
+static int scc_break_ctl(struct tty_struct *tty, int break_state);
+
+static struct tty_driver *scc_driver;
+
+static struct scc_port scc_ports[2];
+
+/*---------------------------------------------------------------------------
+ * Interface from generic_serial.c back here
+ *--------------------------------------------------------------------------*/
+
+static struct real_driver scc_real_driver = {
+        scc_disable_tx_interrupts,
+        scc_enable_tx_interrupts,
+        scc_disable_rx_interrupts,
+        scc_enable_rx_interrupts,
+        scc_shutdown_port,
+        scc_set_real_termios,
+        scc_chars_in_buffer,
+        scc_close,
+        scc_hungup,
+        NULL
+};
+
+
+static const struct tty_operations scc_ops = {
+	.open	= scc_open,
+	.close = gs_close,
+	.write = gs_write,
+	.put_char = gs_put_char,
+	.flush_chars = gs_flush_chars,
+	.write_room = gs_write_room,
+	.chars_in_buffer = gs_chars_in_buffer,
+	.flush_buffer = gs_flush_buffer,
+	.ioctl = scc_ioctl,
+	.throttle = scc_throttle,
+	.unthrottle = scc_unthrottle,
+	.set_termios = gs_set_termios,
+	.stop = gs_stop,
+	.start = gs_start,
+	.hangup = gs_hangup,
+	.break_ctl = scc_break_ctl,
+};
+
+static const struct tty_port_operations scc_port_ops = {
+	.carrier_raised = scc_carrier_raised,
+};
+
+/*----------------------------------------------------------------------------
+ * vme_scc_init() and support functions
+ *---------------------------------------------------------------------------*/
+
+static int __init scc_init_drivers(void)
+{
+	int error;
+
+	scc_driver = alloc_tty_driver(2);
+	if (!scc_driver)
+		return -ENOMEM;
+	scc_driver->owner = THIS_MODULE;
+	scc_driver->driver_name = "scc";
+	scc_driver->name = "ttyS";
+	scc_driver->major = TTY_MAJOR;
+	scc_driver->minor_start = SCC_MINOR_BASE;
+	scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
+	scc_driver->subtype = SERIAL_TYPE_NORMAL;
+	scc_driver->init_termios = tty_std_termios;
+	scc_driver->init_termios.c_cflag =
+	  B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+	scc_driver->init_termios.c_ispeed = 9600;
+	scc_driver->init_termios.c_ospeed = 9600;
+	scc_driver->flags = TTY_DRIVER_REAL_RAW;
+	tty_set_operations(scc_driver, &scc_ops);
+
+	if ((error = tty_register_driver(scc_driver))) {
+		printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n",
+		       error);
+		put_tty_driver(scc_driver);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/* ports[] array is indexed by line no (i.e. [0] for ttyS0, [1] for ttyS1).
+ */
+
+static void __init scc_init_portstructs(void)
+{
+	struct scc_port *port;
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		port = scc_ports + i;
+		tty_port_init(&port->gs.port);
+		port->gs.port.ops = &scc_port_ops;
+		port->gs.magic = SCC_MAGIC;
+		port->gs.close_delay = HZ/2;
+		port->gs.closing_wait = 30 * HZ;
+		port->gs.rd = &scc_real_driver;
+#ifdef NEW_WRITE_LOCKING
+		port->gs.port_write_mutex = MUTEX;
+#endif
+		init_waitqueue_head(&port->gs.port.open_wait);
+		init_waitqueue_head(&port->gs.port.close_wait);
+	}
+}
+
+
+#ifdef CONFIG_MVME147_SCC
+static int __init mvme147_scc_init(void)
+{
+	struct scc_port *port;
+	int error;
+
+	printk(KERN_INFO "SCC: MVME147 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)M147_SCC_A_ADDR;
+	port->datap = port->ctrlp + 1;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-A TX", port);
+	if (error)
+		goto fail;
+	error = request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-A status", port);
+	if (error)
+		goto fail_free_a_tx;
+	error = request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-A RX", port);
+	if (error)
+		goto fail_free_a_stat;
+	error = request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-A special cond", port);
+	if (error)
+		goto fail_free_a_rx;
+
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, MVME147_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)M147_SCC_B_ADDR;
+	port->datap = port->ctrlp + 1;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-B TX", port);
+	if (error)
+		goto fail_free_a_spcond;
+	error = request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-B status", port);
+	if (error)
+		goto fail_free_b_tx;
+	error = request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-B RX", port);
+	if (error)
+		goto fail_free_b_stat;
+	error = request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-B special cond", port);
+	if (error)
+		goto fail_free_b_rx;
+
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+        /* Ensure interrupts are enabled in the PCC chip */
+        m147_pcc->serial_cntrl=PCC_LEVEL_SERIAL|PCC_INT_ENAB;
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+
+fail_free_b_rx:
+	free_irq(MVME147_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+	free_irq(MVME147_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+	free_irq(MVME147_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+	free_irq(MVME147_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+	free_irq(MVME147_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+	free_irq(MVME147_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+	free_irq(MVME147_IRQ_SCCA_TX, port);
+fail:
+	return error;
+}
+#endif
+
+
+#ifdef CONFIG_MVME162_SCC
+static int __init mvme162_scc_init(void)
+{
+	struct scc_port *port;
+	int error;
+
+	if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA))
+		return (-ENODEV);
+
+	printk(KERN_INFO "SCC: MVME162 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)MVME_SCC_A_ADDR;
+	port->datap = port->ctrlp + 2;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-A TX", port);
+	if (error)
+		goto fail;
+	error = request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-A status", port);
+	if (error)
+		goto fail_free_a_tx;
+	error = request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-A RX", port);
+	if (error)
+		goto fail_free_a_stat;
+	error = request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-A special cond", port);
+	if (error)
+		goto fail_free_a_rx;
+
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, MVME162_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)MVME_SCC_B_ADDR;
+	port->datap = port->ctrlp + 2;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-B TX", port);
+	if (error)
+		goto fail_free_a_spcond;
+	error = request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-B status", port);
+	if (error)
+		goto fail_free_b_tx;
+	error = request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-B RX", port);
+	if (error)
+		goto fail_free_b_stat;
+	error = request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-B special cond", port);
+	if (error)
+		goto fail_free_b_rx;
+
+	{
+		SCC_ACCESS_INIT(port);	/* Either channel will do */
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+        /* Ensure interrupts are enabled in the MC2 chip */
+        *(volatile char *)0xfff4201d = 0x14;
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+
+fail_free_b_rx:
+	free_irq(MVME162_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+	free_irq(MVME162_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+	free_irq(MVME162_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+	free_irq(MVME162_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+	free_irq(MVME162_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+	free_irq(MVME162_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+	free_irq(MVME162_IRQ_SCCA_TX, port);
+fail:
+	return error;
+}
+#endif
+
+
+#ifdef CONFIG_BVME6000_SCC
+static int __init bvme6000_scc_init(void)
+{
+	struct scc_port *port;
+	int error;
+
+	printk(KERN_INFO "SCC: BVME6000 Serial Driver\n");
+	/* Init channel A */
+	port = &scc_ports[0];
+	port->channel = CHANNEL_A;
+	port->ctrlp = (volatile unsigned char *)BVME_SCC_A_ADDR;
+	port->datap = port->ctrlp + 4;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-A TX", port);
+	if (error)
+		goto fail;
+	error = request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-A status", port);
+	if (error)
+		goto fail_free_a_tx;
+	error = request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-A RX", port);
+	if (error)
+		goto fail_free_a_stat;
+	error = request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-A special cond", port);
+	if (error)
+		goto fail_free_a_rx;
+
+	{
+		SCC_ACCESS_INIT(port);
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+		/* Set the interrupt vector */
+		SCCwrite(INT_VECTOR_REG, BVME_IRQ_SCC_BASE);
+		/* Interrupt parameters: vector includes status, status low */
+		SCCwrite(MASTER_INT_CTRL, MIC_VEC_INCL_STAT);
+		SCCmod(MASTER_INT_CTRL, 0xff, MIC_MASTER_INT_ENAB);
+	}
+
+	/* Init channel B */
+	port = &scc_ports[1];
+	port->channel = CHANNEL_B;
+	port->ctrlp = (volatile unsigned char *)BVME_SCC_B_ADDR;
+	port->datap = port->ctrlp + 4;
+	port->port_a = &scc_ports[0];
+	port->port_b = &scc_ports[1];
+	error = request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
+		            "SCC-B TX", port);
+	if (error)
+		goto fail_free_a_spcond;
+	error = request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
+		            "SCC-B status", port);
+	if (error)
+		goto fail_free_b_tx;
+	error = request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
+		            "SCC-B RX", port);
+	if (error)
+		goto fail_free_b_stat;
+	error = request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int,
+			    IRQF_DISABLED, "SCC-B special cond", port);
+	if (error)
+		goto fail_free_b_rx;
+
+	{
+		SCC_ACCESS_INIT(port);	/* Either channel will do */
+
+		/* disable interrupts for this channel */
+		SCCwrite(INT_AND_DMA_REG, 0);
+	}
+
+	/* Initialise the tty driver structures and register */
+	scc_init_portstructs();
+	scc_init_drivers();
+
+	return 0;
+
+fail:
+	free_irq(BVME_IRQ_SCCA_STAT, port);
+fail_free_a_tx:
+	free_irq(BVME_IRQ_SCCA_RX, port);
+fail_free_a_stat:
+	free_irq(BVME_IRQ_SCCA_SPCOND, port);
+fail_free_a_rx:
+	free_irq(BVME_IRQ_SCCB_TX, port);
+fail_free_a_spcond:
+	free_irq(BVME_IRQ_SCCB_STAT, port);
+fail_free_b_tx:
+	free_irq(BVME_IRQ_SCCB_RX, port);
+fail_free_b_stat:
+	free_irq(BVME_IRQ_SCCB_SPCOND, port);
+fail_free_b_rx:
+	return error;
+}
+#endif
+
+
+static int __init vme_scc_init(void)
+{
+	int res = -ENODEV;
+
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		res = mvme147_scc_init();
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		res = mvme162_scc_init();
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		res = bvme6000_scc_init();
+#endif
+	return res;
+}
+
+module_init(vme_scc_init);
+
+
+/*---------------------------------------------------------------------------
+ * Interrupt handlers
+ *--------------------------------------------------------------------------*/
+
+static irqreturn_t scc_rx_int(int irq, void *data)
+{
+	unsigned char	ch;
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.port.tty;
+	SCC_ACCESS_INIT(port);
+
+	ch = SCCread_NB(RX_DATA_REG);
+	if (!tty) {
+		printk(KERN_WARNING "scc_rx_int with NULL tty!\n");
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return IRQ_HANDLED;
+	}
+	tty_insert_flip_char(tty, ch, 0);
+
+	/* Check if another character is already ready; in that case, the
+	 * spcond_int() function must be used, because this character may have an
+	 * error condition that isn't signalled by the interrupt vector used!
+	 */
+	if (SCCread(INT_PENDING_REG) &
+	    (port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
+		scc_spcond_int (irq, data);
+		return IRQ_HANDLED;
+	}
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+	tty_flip_buffer_push(tty);
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t scc_spcond_int(int irq, void *data)
+{
+	struct scc_port *port = data;
+	struct tty_struct *tty = port->gs.port.tty;
+	unsigned char	stat, ch, err;
+	int		int_pending_mask = port->channel == CHANNEL_A ?
+			                   IPR_A_RX : IPR_B_RX;
+	SCC_ACCESS_INIT(port);
+	
+	if (!tty) {
+		printk(KERN_WARNING "scc_spcond_int with NULL tty!\n");
+		SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return IRQ_HANDLED;
+	}
+	do {
+		stat = SCCread(SPCOND_STATUS_REG);
+		ch = SCCread_NB(RX_DATA_REG);
+
+		if (stat & SCSR_RX_OVERRUN)
+			err = TTY_OVERRUN;
+		else if (stat & SCSR_PARITY_ERR)
+			err = TTY_PARITY;
+		else if (stat & SCSR_CRC_FRAME_ERR)
+			err = TTY_FRAME;
+		else
+			err = 0;
+
+		tty_insert_flip_char(tty, ch, err);
+
+		/* ++TeSche: *All* errors have to be cleared manually,
+		 * else the condition persists for the next chars
+		 */
+		if (err)
+		  SCCwrite(COMMAND_REG, CR_ERROR_RESET);
+
+	} while(SCCread(INT_PENDING_REG) & int_pending_mask);
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+
+	tty_flip_buffer_push(tty);
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t scc_tx_int(int irq, void *data)
+{
+	struct scc_port *port = data;
+	SCC_ACCESS_INIT(port);
+
+	if (!port->gs.port.tty) {
+		printk(KERN_WARNING "scc_tx_int with NULL tty!\n");
+		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);
+		SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+		return IRQ_HANDLED;
+	}
+	while ((SCCread_NB(STATUS_REG) & SR_TX_BUF_EMPTY)) {
+		if (port->x_char) {
+			SCCwrite(TX_DATA_REG, port->x_char);
+			port->x_char = 0;
+		}
+		else if ((port->gs.xmit_cnt <= 0) ||
+			 port->gs.port.tty->stopped ||
+			 port->gs.port.tty->hw_stopped)
+			break;
+		else {
+			SCCwrite(TX_DATA_REG, port->gs.xmit_buf[port->gs.xmit_tail++]);
+			port->gs.xmit_tail = port->gs.xmit_tail & (SERIAL_XMIT_SIZE-1);
+			if (--port->gs.xmit_cnt <= 0)
+				break;
+		}
+	}
+	if ((port->gs.xmit_cnt <= 0) || port->gs.port.tty->stopped ||
+	    port->gs.port.tty->hw_stopped) {
+		/* disable tx interrupts */
+		SCCmod (INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+		SCCwrite(COMMAND_REG, CR_TX_PENDING_RESET);   /* disable tx_int on next tx underrun? */
+		port->gs.port.flags &= ~GS_TX_INTEN;
+	}
+	if (port->gs.port.tty && port->gs.xmit_cnt <= port->gs.wakeup_chars)
+		tty_wakeup(port->gs.port.tty);
+
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t scc_stat_int(int irq, void *data)
+{
+	struct scc_port *port = data;
+	unsigned channel = port->channel;
+	unsigned char	last_sr, sr, changed;
+	SCC_ACCESS_INIT(port);
+
+	last_sr = scc_last_status_reg[channel];
+	sr = scc_last_status_reg[channel] = SCCread_NB(STATUS_REG);
+	changed = last_sr ^ sr;
+
+	if (changed & SR_DCD) {
+		port->c_dcd = !!(sr & SR_DCD);
+		if (!(port->gs.port.flags & ASYNC_CHECK_CD))
+			;	/* Don't report DCD changes */
+		else if (port->c_dcd) {
+			wake_up_interruptible(&port->gs.port.open_wait);
+		}
+		else {
+			if (port->gs.port.tty)
+				tty_hangup (port->gs.port.tty);
+		}
+	}
+	SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET);
+	SCCwrite_NB(COMMAND_REG, CR_HIGHEST_IUS_RESET);
+	return IRQ_HANDLED;
+}
+
+
+/*---------------------------------------------------------------------------
+ * generic_serial.c callback funtions
+ *--------------------------------------------------------------------------*/
+
+static void scc_disable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	SCCmod(INT_AND_DMA_REG, ~IDR_TX_INT_ENAB, 0);
+	port->gs.port.flags &= ~GS_TX_INTEN;
+	local_irq_restore(flags);
+}
+
+
+static void scc_enable_tx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
+	/* restart the transmitter */
+	scc_tx_int (0, port);
+	local_irq_restore(flags);
+}
+
+
+static void scc_disable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	SCCmod(INT_AND_DMA_REG,
+	    ~(IDR_RX_INT_MASK|IDR_PARERR_AS_SPCOND|IDR_EXTSTAT_INT_ENAB), 0);
+	local_irq_restore(flags);
+}
+
+
+static void scc_enable_rx_interrupts(void *ptr)
+{
+	struct scc_port *port = ptr;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	SCCmod(INT_AND_DMA_REG, 0xff,
+		IDR_EXTSTAT_INT_ENAB|IDR_PARERR_AS_SPCOND|IDR_RX_INT_ALL);
+	local_irq_restore(flags);
+}
+
+
+static int scc_carrier_raised(struct tty_port *port)
+{
+	struct scc_port *sc = container_of(port, struct scc_port, gs.port);
+	unsigned channel = sc->channel;
+
+	return !!(scc_last_status_reg[channel] & SR_DCD);
+}
+
+
+static void scc_shutdown_port(void *ptr)
+{
+	struct scc_port *port = ptr;
+
+	port->gs.port.flags &= ~ GS_ACTIVE;
+	if (port->gs.port.tty && (port->gs.port.tty->termios->c_cflag & HUPCL)) {
+		scc_setsignals (port, 0, 0);
+	}
+}
+
+
+static int scc_set_real_termios (void *ptr)
+{
+	/* the SCC has char sizes 5,7,6,8 in that order! */
+	static int chsize_map[4] = { 0, 2, 1, 3 };
+	unsigned cflag, baud, chsize, channel, brgval = 0;
+	unsigned long flags;
+	struct scc_port *port = ptr;
+	SCC_ACCESS_INIT(port);
+
+	if (!port->gs.port.tty || !port->gs.port.tty->termios) return 0;
+
+	channel = port->channel;
+
+	if (channel == CHANNEL_A)
+		return 0;		/* Settings controlled by boot PROM */
+
+	cflag  = port->gs.port.tty->termios->c_cflag;
+	baud = port->gs.baud;
+	chsize = (cflag & CSIZE) >> 4;
+
+	if (baud == 0) {
+		/* speed == 0 -> drop DTR */
+		local_irq_save(flags);
+		SCCmod(TX_CTRL_REG, ~TCR_DTR, 0);
+		local_irq_restore(flags);
+		return 0;
+	}
+	else if ((MACH_IS_MVME16x && (baud < 50 || baud > 38400)) ||
+		 (MACH_IS_MVME147 && (baud < 50 || baud > 19200)) ||
+		 (MACH_IS_BVME6000 &&(baud < 50 || baud > 76800))) {
+		printk(KERN_NOTICE "SCC: Bad speed requested, %d\n", baud);
+		return 0;
+	}
+
+	if (cflag & CLOCAL)
+		port->gs.port.flags &= ~ASYNC_CHECK_CD;
+	else
+		port->gs.port.flags |= ASYNC_CHECK_CD;
+
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		brgval = (M147_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		brgval = (MVME_SCC_PCLK + baud/2) / (16 * 2 * baud) - 2;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		brgval = (BVME_SCC_RTxC + baud/2) / (16 * 2 * baud) - 2;
+#endif
+	/* Now we have all parameters and can go to set them: */
+	local_irq_save(flags);
+
+	/* receiver's character size and auto-enables */
+	SCCmod(RX_CTRL_REG, ~(RCR_CHSIZE_MASK|RCR_AUTO_ENAB_MODE),
+			(chsize_map[chsize] << 6) |
+			((cflag & CRTSCTS) ? RCR_AUTO_ENAB_MODE : 0));
+	/* parity and stop bits (both, Tx and Rx), clock mode never changes */
+	SCCmod (AUX1_CTRL_REG,
+		~(A1CR_PARITY_MASK | A1CR_MODE_MASK),
+		((cflag & PARENB
+		  ? (cflag & PARODD ? A1CR_PARITY_ODD : A1CR_PARITY_EVEN)
+		  : A1CR_PARITY_NONE)
+		 | (cflag & CSTOPB ? A1CR_MODE_ASYNC_2 : A1CR_MODE_ASYNC_1)));
+	/* sender's character size, set DTR for valid baud rate */
+	SCCmod(TX_CTRL_REG, ~TCR_CHSIZE_MASK, chsize_map[chsize] << 5 | TCR_DTR);
+	/* clock sources never change */
+	/* disable BRG before changing the value */
+	SCCmod(DPLL_CTRL_REG, ~DCR_BRG_ENAB, 0);
+	/* BRG value */
+	SCCwrite(TIMER_LOW_REG, brgval & 0xff);
+	SCCwrite(TIMER_HIGH_REG, (brgval >> 8) & 0xff);
+	/* BRG enable, and clock source never changes */
+	SCCmod(DPLL_CTRL_REG, 0xff, DCR_BRG_ENAB);
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+
+static int scc_chars_in_buffer (void *ptr)
+{
+	struct scc_port *port = ptr;
+	SCC_ACCESS_INIT(port);
+
+	return (SCCread (SPCOND_STATUS_REG) & SCSR_ALL_SENT) ? 0  : 1;
+}
+
+
+/* Comment taken from sx.c (2.4.0):
+   I haven't the foggiest why the decrement use count has to happen
+   here. The whole linux serial drivers stuff needs to be redesigned.
+   My guess is that this is a hack to minimize the impact of a bug
+   elsewhere. Thinking about it some more. (try it sometime) Try
+   running minicom on a serial port that is driven by a modularized
+   driver. Have the modem hangup. Then remove the driver module. Then
+   exit minicom.  I expect an "oops".  -- REW */
+
+static void scc_hungup(void *ptr)
+{
+	scc_disable_tx_interrupts(ptr);
+	scc_disable_rx_interrupts(ptr);
+}
+
+
+static void scc_close(void *ptr)
+{
+	scc_disable_tx_interrupts(ptr);
+	scc_disable_rx_interrupts(ptr);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Internal support functions
+ *--------------------------------------------------------------------------*/
+
+static void scc_setsignals(struct scc_port *port, int dtr, int rts)
+{
+	unsigned long flags;
+	unsigned char t;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	t = SCCread(TX_CTRL_REG);
+	if (dtr >= 0) t = dtr? (t | TCR_DTR): (t & ~TCR_DTR);
+	if (rts >= 0) t = rts? (t | TCR_RTS): (t & ~TCR_RTS);
+	SCCwrite(TX_CTRL_REG, t);
+	local_irq_restore(flags);
+}
+
+
+static void scc_send_xchar(struct tty_struct *tty, char ch)
+{
+	struct scc_port *port = tty->driver_data;
+
+	port->x_char = ch;
+	if (ch)
+		scc_enable_tx_interrupts(port);
+}
+
+
+/*---------------------------------------------------------------------------
+ * Driver entrypoints referenced from above
+ *--------------------------------------------------------------------------*/
+
+static int scc_open (struct tty_struct * tty, struct file * filp)
+{
+	int line = tty->index;
+	int retval;
+	struct scc_port *port = &scc_ports[line];
+	int i, channel = port->channel;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+#if defined(CONFIG_MVME162_SCC) || defined(CONFIG_MVME147_SCC)
+	static const struct {
+		unsigned reg, val;
+	} mvme_init_tab[] = {
+		/* Values for MVME162 and MVME147 */
+		/* no parity, 1 stop bit, async, 1:16 */
+		{ AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+		/* parity error is special cond, ints disabled, no DMA */
+		{ INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+		/* Rx 8 bits/char, no auto enable, Rx off */
+		{ RX_CTRL_REG, RCR_CHSIZE_8 },
+		/* DTR off, Tx 8 bits/char, RTS off, Tx off */
+		{ TX_CTRL_REG, TCR_CHSIZE_8 },
+		/* special features off */
+		{ AUX2_CTRL_REG, 0 },
+		{ CLK_CTRL_REG, CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+		{ DPLL_CTRL_REG, DCR_BRG_ENAB | DCR_BRG_USE_PCLK },
+		/* Start Rx */
+		{ RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+		/* Start Tx */
+		{ TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+		/* Ext/Stat ints: DCD only */
+		{ INT_CTRL_REG, ICR_ENAB_DCD_INT },
+		/* Reset Ext/Stat ints */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+		/* ...again */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+	};
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+	static const struct {
+		unsigned reg, val;
+	} bvme_init_tab[] = {
+		/* Values for BVME6000 */
+		/* no parity, 1 stop bit, async, 1:16 */
+		{ AUX1_CTRL_REG, A1CR_PARITY_NONE|A1CR_MODE_ASYNC_1|A1CR_CLKMODE_x16 },
+		/* parity error is special cond, ints disabled, no DMA */
+		{ INT_AND_DMA_REG, IDR_PARERR_AS_SPCOND | IDR_RX_INT_DISAB },
+		/* Rx 8 bits/char, no auto enable, Rx off */
+		{ RX_CTRL_REG, RCR_CHSIZE_8 },
+		/* DTR off, Tx 8 bits/char, RTS off, Tx off */
+		{ TX_CTRL_REG, TCR_CHSIZE_8 },
+		/* special features off */
+		{ AUX2_CTRL_REG, 0 },
+		{ CLK_CTRL_REG, CCR_RTxC_XTAL | CCR_RXCLK_BRG | CCR_TXCLK_BRG },
+		{ DPLL_CTRL_REG, DCR_BRG_ENAB },
+		/* Start Rx */
+		{ RX_CTRL_REG, RCR_RX_ENAB | RCR_CHSIZE_8 },
+		/* Start Tx */
+		{ TX_CTRL_REG, TCR_TX_ENAB | TCR_RTS | TCR_DTR | TCR_CHSIZE_8 },
+		/* Ext/Stat ints: DCD only */
+		{ INT_CTRL_REG, ICR_ENAB_DCD_INT },
+		/* Reset Ext/Stat ints */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+		/* ...again */
+		{ COMMAND_REG, CR_EXTSTAT_RESET },
+	};
+#endif
+	if (!(port->gs.port.flags & ASYNC_INITIALIZED)) {
+		local_irq_save(flags);
+#if defined(CONFIG_MVME147_SCC) || defined(CONFIG_MVME162_SCC)
+		if (MACH_IS_MVME147 || MACH_IS_MVME16x) {
+			for (i = 0; i < ARRAY_SIZE(mvme_init_tab); ++i)
+				SCCwrite(mvme_init_tab[i].reg, mvme_init_tab[i].val);
+		}
+#endif
+#if defined(CONFIG_BVME6000_SCC)
+		if (MACH_IS_BVME6000) {
+			for (i = 0; i < ARRAY_SIZE(bvme_init_tab); ++i)
+				SCCwrite(bvme_init_tab[i].reg, bvme_init_tab[i].val);
+		}
+#endif
+
+		/* remember status register for detection of DCD and CTS changes */
+		scc_last_status_reg[channel] = SCCread(STATUS_REG);
+
+		port->c_dcd = 0;	/* Prevent initial 1->0 interrupt */
+		scc_setsignals (port, 1,1);
+		local_irq_restore(flags);
+	}
+
+	tty->driver_data = port;
+	port->gs.port.tty = tty;
+	port->gs.port.count++;
+	retval = gs_init_port(&port->gs);
+	if (retval) {
+		port->gs.port.count--;
+		return retval;
+	}
+	port->gs.port.flags |= GS_ACTIVE;
+	retval = gs_block_til_ready(port, filp);
+
+	if (retval) {
+		port->gs.port.count--;
+		return retval;
+	}
+
+	port->c_dcd = tty_port_carrier_raised(&port->gs.port);
+
+	scc_enable_rx_interrupts(port);
+
+	return 0;
+}
+
+
+static void scc_throttle (struct tty_struct * tty)
+{
+	struct scc_port *port = tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		local_irq_save(flags);
+		SCCmod(TX_CTRL_REG, ~TCR_RTS, 0);
+		local_irq_restore(flags);
+	}
+	if (I_IXOFF(tty))
+		scc_send_xchar(tty, STOP_CHAR(tty));
+}
+
+
+static void scc_unthrottle (struct tty_struct * tty)
+{
+	struct scc_port *port = tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	if (tty->termios->c_cflag & CRTSCTS) {
+		local_irq_save(flags);
+		SCCmod(TX_CTRL_REG, 0xff, TCR_RTS);
+		local_irq_restore(flags);
+	}
+	if (I_IXOFF(tty))
+		scc_send_xchar(tty, START_CHAR(tty));
+}
+
+
+static int scc_ioctl(struct tty_struct *tty,
+		     unsigned int cmd, unsigned long arg)
+{
+	return -ENOIOCTLCMD;
+}
+
+
+static int scc_break_ctl(struct tty_struct *tty, int break_state)
+{
+	struct scc_port *port = tty->driver_data;
+	unsigned long	flags;
+	SCC_ACCESS_INIT(port);
+
+	local_irq_save(flags);
+	SCCmod(TX_CTRL_REG, ~TCR_SEND_BREAK, 
+			break_state ? TCR_SEND_BREAK : 0);
+	local_irq_restore(flags);
+	return 0;
+}
+
+
+/*---------------------------------------------------------------------------
+ * Serial console stuff...
+ *--------------------------------------------------------------------------*/
+
+#define scc_delay() do { __asm__ __volatile__ (" nop; nop"); } while (0)
+
+static void scc_ch_write (char ch)
+{
+	volatile char *p = NULL;
+	
+#ifdef CONFIG_MVME147_SCC
+	if (MACH_IS_MVME147)
+		p = (volatile char *)M147_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_MVME162_SCC
+	if (MACH_IS_MVME16x)
+		p = (volatile char *)MVME_SCC_A_ADDR;
+#endif
+#ifdef CONFIG_BVME6000_SCC
+	if (MACH_IS_BVME6000)
+		p = (volatile char *)BVME_SCC_A_ADDR;
+#endif
+
+	do {
+		scc_delay();
+	}
+	while (!(*p & 4));
+	scc_delay();
+	*p = 8;
+	scc_delay();
+	*p = ch;
+}
+
+/* The console must be locked when we get here. */
+
+static void scc_console_write (struct console *co, const char *str, unsigned count)
+{
+	unsigned long	flags;
+
+	local_irq_save(flags);
+
+	while (count--)
+	{
+		if (*str == '\n')
+			scc_ch_write ('\r');
+		scc_ch_write (*str++);
+	}
+	local_irq_restore(flags);
+}
+
+static struct tty_driver *scc_console_device(struct console *c, int *index)
+{
+	*index = c->index;
+	return scc_driver;
+}
+
+static struct console sercons = {
+	.name		= "ttyS",
+	.write		= scc_console_write,
+	.device		= scc_console_device,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+};
+
+
+static int __init vme_scc_console_init(void)
+{
+	if (vme_brdtype == VME_TYPE_MVME147 ||
+			vme_brdtype == VME_TYPE_MVME162 ||
+			vme_brdtype == VME_TYPE_MVME172 ||
+			vme_brdtype == VME_TYPE_BVME4000 ||
+			vme_brdtype == VME_TYPE_BVME6000)
+		register_console(&sercons);
+	return 0;
+}
+console_initcall(vme_scc_console_init);