Psion serial driver patch for linux/drivers/serial/ files

This patch contains updates to the following files:
./drivers/serial/Config.in
./drivers/serial/Makefile
./drivers/serial/serial_core.c
./drivers/serial/serial_psionw.c
./drivers/serial/serial_psionw.h


diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Config.in linux-2.4.19-rmk2/drivers/serial/Config.in
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Config.in linux-2.4.19-rmk2/drivers/serial/Config.in
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Config.in	2002-10-02 22:05:24.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/serial/Config.in	2002-10-02 22:07:30.000000000 -0700
@@ -23,6 +23,9 @@
   dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X
   dep_bool '  Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X
 
+  dep_tristate 'Psion serial port support' CONFIG_SERIAL_PSIONW $CONFIG_ARCH_PSIONW
+  dep_bool '  Support for console on Psion serial port' CONFIG_SERIAL_PSIONW_CONSOLE $CONFIG_SERIAL_PSIONW
+
   dep_bool 'DC21285 serial port support' CONFIG_SERIAL_21285 $CONFIG_FOOTBRIDGE
   dep_bool '  Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD $CONFIG_SERIAL_21285 $CONFIG_OBSOLETE
   dep_bool '  Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE $CONFIG_SERIAL_21285
@@ -51,6 +54,7 @@
 
 if [ "$CONFIG_SERIAL_AMBA" = "y" -o \
      "$CONFIG_SERIAL_CLPS711X" = "y" -o \
+     "$CONFIG_SERIAL_PSIONW" = "y" -o \
      "$CONFIG_SERIAL_SA1100" = "y" -o \
      "$CONFIG_SERIAL_ANAKIN" = "y" -o \
      "$CONFIG_SERIAL_UART00" = "y" -o \
@@ -59,6 +63,7 @@
 else
    if [ "$CONFIG_SERIAL_AMBA" = "m" -o \
         "$CONFIG_SERIAL_CLPS711X" = "m" -o \
+        "$CONFIG_SERIAL_PSIONW" = "m" -o \
         "$CONFIG_SERIAL_SA1100" = "m" -o \
         "$CONFIG_SERIAL_ANAKIN" = "m" -o \
         "$CONFIG_SERIAL_UART00" = "m" -o \
@@ -68,6 +73,7 @@
 fi
 if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \
      "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \
+     "$CONFIG_SERIAL_PSIONW_CONSOLE" = "y" -o \
      "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \
      "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \
      "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Makefile linux-2.4.19-rmk2/drivers/serial/Makefile
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Makefile linux-2.4.19-rmk2/drivers/serial/Makefile
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/Makefile	2002-10-02 22:05:25.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/serial/Makefile	2002-10-02 22:07:30.000000000 -0700
@@ -28,6 +28,7 @@
 obj-$(CONFIG_SERIAL_ANAKIN) += serial_anakin.o
 obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o
 obj-$(CONFIG_SERIAL_CLPS711X) += serial_clps711x.o
+obj-$(CONFIG_SERIAL_PSIONW) += serial_psionw.o
 obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o
 obj-$(CONFIG_SERIAL_UART00) += serial_uart00.o
 
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_core.c linux-2.4.19-rmk2/drivers/serial/serial_core.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_core.c linux-2.4.19-rmk2/drivers/serial/serial_core.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_core.c	2002-10-02 22:05:25.000000000 -0700
+++ linux-2.4.19-rmk2/drivers/serial/serial_core.c	2002-10-02 22:07:30.000000000 -0700
@@ -1710,6 +1710,7 @@
 extern void ambauart_console_init(void);
 extern void anakin_console_init(void);
 extern void clps711xuart_console_init(void);
+extern void psionw_console_init(void);
 extern void rs285_console_init(void);
 extern void sa1100_rs_console_init(void);
 extern void serial8250_console_init(void);
@@ -1728,6 +1729,9 @@
 #ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
 	clps711xuart_console_init();
 #endif
+#ifdef CONFIG_SERIAL_PSIONW_CONSOLE
+        psionwuart_console_init();
+#endif
 #ifdef CONFIG_SERIAL_21285_CONSOLE
 	rs285_console_init();
 #endif
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.c linux-2.4.19-rmk2/drivers/serial/serial_psionw.c
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.c linux-2.4.19-rmk2/drivers/serial/serial_psionw.c
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/serial/serial_psionw.c	2002-10-06 14:19:37.000000000 -0700
@@ -0,0 +1,789 @@
+/*
+ *  linux/drivers/char/serial_psionw.c
+ *
+ *  Copyright (C) 2001 Yuji Shinokawa <ysh@mob.or.jp>
+ *
+ *  Written by Yuji Shinokawa, Irda port support and generic 
+ *  updates by Tony Lindgren <tony@atomide.com>
+ *
+ *  Based on the clps711x code, some portions of the code
+ *  Copyright (C) 2000 Deep Blue Solutions Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/circ_buf.h>
+#include <linux/serial.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/bitops.h>
+
+#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+#include "serial_psionw.h"
+
+#define UART_NR		2
+
+#define SERIAL_PSIONW_NAME	"ttyAM"
+#define SERIAL_PSIONW_MAJOR	204
+#define SERIAL_PSIONW_MINOR	16
+#define SERIAL_PSIONW_NR	UART_NR
+
+#define CALLOUT_PSIONW_NAME	"cuaam"
+#define CALLOUT_PSIONW_MAJOR	205
+#define CALLOUT_PSIONW_MINOR	16
+#define CALLOUT_PSIONW_NR	UART_NR
+
+static struct tty_driver normal, callout;
+static struct tty_struct *psionw_table[UART_NR];
+static struct termios *psionw_termios[UART_NR],*psionw_termios_locked[UART_NR];
+#ifdef SUPPORT_SYSRQ
+static struct console psionw_console;
+#endif
+
+static void
+psionwuart_stop_tx(struct uart_port *port, u_int from_tty)
+{
+	u_int uartintm;
+
+	uartintm = UART_GET_INT_MASK(port);
+	uartintm &= ~PSIONW_UART_TXINT;
+	UART_PUT_INT_MASK(port, uartintm);
+}
+
+static void
+psionwuart_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
+{
+	u_int uartintm;
+
+	if (nonempty) {
+		uartintm = UART_GET_INT_MASK(port);
+		uartintm |= PSIONW_UART_TXINT;
+		UART_PUT_INT_MASK(port, uartintm);
+	}
+}
+
+static void
+psionwuart_stop_rx(struct uart_port *port)
+{
+	u_int uartintm;
+
+	uartintm = UART_GET_INT_MASK(port);
+	uartintm &= ~PSIONW_UART_RXINT;
+	UART_PUT_INT_MASK(port, uartintm);
+}
+
+static void
+psionwuart_enable_ms(struct uart_port *port)
+{
+	u_int uartintm;
+
+	uartintm = UART_GET_INT_MASK(port);
+	uartintm |= PSIONW_UART_MSINT;
+	UART_PUT_INT_MASK(port, uartintm);
+}
+
+static void
+#ifdef SUPPORT_SYSRQ
+psionwuart_rx_chars(struct uart_info *info, struct pt_regs *regs)
+#else
+psionwuart_rx_chars(struct uart_info *info)
+#endif
+{
+	struct tty_struct *tty = info->tty;
+	unsigned int status, ch, rsr, max_count = 256;
+	struct uart_port *port = info->port;
+
+	status = UART_GET_FR(port);
+	while (UART_RX_DATA(status) && max_count--) {
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			tty->flip.tqueue.routine((void *) tty);
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
+				return;
+			}
+		}
+
+		/* Get the data plus 3 error bits */
+		rsr = UART_GET_CHAR(port);
+		ch = (rsr & 0xff);
+
+		*tty->flip.char_buf_ptr = ch;
+		*tty->flip.flag_buf_ptr = TTY_NORMAL;
+		port->icount.rx++;
+
+		/*
+		 * Note that the error handling code is
+		 * out of the main execution path.
+		 * Note also that psionw has the error bits
+		 * in the data register.
+		 */
+		//rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX;
+		//rsr |= UART_DUMMY_RSR_RX;
+		if (rsr & PSIONW_UARTRSR_ANY) {
+			if (rsr & PSIONW_UARTRSR_PE) {
+				port->icount.parity++;
+			} else if (rsr & PSIONW_UARTRSR_FE) {
+				port->icount.frame++;
+			}
+			if (rsr & PSIONW_UARTRSR_OE) {
+				port->icount.overrun++;
+			}
+			rsr &= port->read_status_mask;
+			if (rsr & PSIONW_UARTRSR_PE)
+				*tty->flip.flag_buf_ptr = TTY_PARITY;
+			else if (rsr & PSIONW_UARTRSR_FE)
+				*tty->flip.flag_buf_ptr = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(info, ch, regs))
+			goto ignore_char;
+
+		if ((rsr & port->ignore_status_mask) == 0) {
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+		if ((rsr & PSIONW_UARTRSR_OE) &&
+		    tty->flip.count < TTY_FLIPBUF_SIZE) {
+			/*
+			 * Overrun is special, since it's reported
+			 * immediately, and doesn't affect the current
+			 * character
+			 */
+			*tty->flip.char_buf_ptr++ = 0;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			tty->flip.count++;
+		}
+	      ignore_char:
+		status = UART_GET_FR(port);
+	}
+	tty_flip_buffer_push(tty);
+	return;
+}
+
+static void
+psionwuart_tx_chars(struct uart_info *info)
+{
+	struct uart_port *port = info->port;
+	int count;
+	unsigned int status;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (info->xmit.head == info->xmit.tail
+	    || info->tty->stopped || info->tty->hw_stopped) {
+		psionwuart_stop_tx(port, 0);
+		return;
+	}
+
+	count = port->fifosize >> 1;
+	do {
+		UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (info->xmit.head == info->xmit.tail)
+			break;
+	} while (--count > 0);
+
+	if (CIRC_CNT(info->xmit.head, info->xmit.tail, UART_XMIT_SIZE) <
+	    WAKEUP_CHARS)
+		uart_event(info, EVT_WRITE_WAKEUP);
+
+	if (info->xmit.head == info->xmit.tail)
+		psionwuart_stop_tx(info->port, 0);
+}
+
+static u_int
+psionwuart_tx_empty(struct uart_port *port)
+{
+	u_int status = UART_GET_FR(port);
+	return status & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT;
+}
+
+static int
+psionwuart_get_mctrl(struct uart_port *port)
+{
+	unsigned int result = 0;
+	unsigned int status;
+
+	status = UART_GET_FR(port);
+	if (status & AMBA_UARTFR_DCD)
+		result |= TIOCM_CAR;
+	if (status & AMBA_UARTFR_DSR)
+		result |= TIOCM_DSR;
+	if (status & AMBA_UARTFR_CTS)
+		result |= TIOCM_CTS;
+
+	return result;
+}
+
+static void
+psionwuart_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	unsigned int pcdr = 0;
+
+	/* NOTE: printk's here will corrupt the terminal */
+	if ((mctrl & TIOCM_RTS) == TIOCM_RTS) {
+		pcdr = psionw_readl(PCDR);
+		if (port->mapbase == PSIONW_UART0_V_BASE) {
+			pcdr |= PCDR_UART1;
+		} else if (port->mapbase == PSIONW_UART1_V_BASE) {
+			pcdr |= PCDR_UART2;
+		}
+		psionw_writel(pcdr, PCDR);
+	}
+}
+
+static void
+psionwuart_break_ctl(struct uart_port *port, int break_state)
+{
+	unsigned int ubrfcr;
+
+	ubrfcr = UART_GET_FCR(port);
+	if (break_state == -1)
+		ubrfcr |= PSIONW_UARTFCR_BREAK;
+	else
+		ubrfcr &= ~PSIONW_UARTFCR_BREAK;
+	UART_PUT_FCR(port, ubrfcr);
+}
+
+/*
+ * Only used for the UART1, the Irda port does not support this.
+ */
+static void
+psionwuart_modem_status(struct uart_info *info)
+{
+	struct uart_port *port = info->port;
+	unsigned int status, delta;
+
+	status = UART_GET_FR(port) & PSIONW_UARTFR_MODEM_ANY;
+	psionw_writel(0, UMSEOI);
+
+	delta = status ^ info->driver_priv;
+	info->driver_priv = status;
+
+	if (!delta)
+		return;
+
+	if (delta & AMBA_UARTFR_DCD)
+		uart_handle_dcd_change(info, status & AMBA_UARTFR_DCD);
+
+	if (delta & AMBA_UARTFR_DSR)
+		port->icount.dsr++;
+
+	if (delta & AMBA_UARTFR_CTS)
+		uart_handle_cts_change(info, status & AMBA_UARTFR_CTS);
+
+	wake_up_interruptible(&info->delta_msr_wait);
+}
+
+/*
+ * Serial interrupts
+ */
+static void
+psionwuart_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_info *info = dev_id;
+	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
+	unsigned int psionwuart_int_mask = 
+		(PSIONW_UART_RXINT | PSIONW_UART_TXINT | PSIONW_UART_MSINT);
+
+	/* Irda port does not support modem status */
+	if (info->port->mapbase == PSIONW_UART0_V_BASE)
+		psionwuart_int_mask = (PSIONW_UART_RXINT | PSIONW_UART_TXINT);
+
+	status = UART_GET_INT_STATUS(info->port);
+	do {
+		if (status & PSIONW_UART_RXINT) {
+#ifdef SUPPORT_SYSRQ
+			psionwuart_rx_chars(info, regs);
+#else
+			psionwuart_rx_chars(info);
+#endif
+		}
+		if (status & PSIONW_UART_TXINT) {
+			psionwuart_tx_chars(info);
+		}
+		if ((status & PSIONW_UART_MSINT)
+		    && (info->port->mapbase == PSIONW_UART1_V_BASE)) {
+
+			/* Clear modem status interrupt */
+			UART_CLEAR_INT(info->port, 1);
+
+			psionwuart_modem_status(info);
+		}
+		if (pass_counter-- == 0) {
+			break;
+		}
+		status = UART_GET_INT_STATUS(info->port);
+	} while (status & psionwuart_int_mask);
+}
+
+static int
+psionwuart_startup(struct uart_port *port, struct uart_info *info)
+{
+	u_int cfg;
+	int retval;
+	u_int uartintm;
+
+	/*
+	 * Allocate the IRQs
+	 */
+	retval = request_irq(port->irq, psionwuart_int, 0, "psionwuart", info);
+	if (retval)
+		return retval;
+
+	/*
+	 * initialise the old status of the modem signals
+	 */
+	info->driver_priv = UART_GET_FR(port) & PSIONW_UARTFR_MODEM_ANY;
+
+	/*
+	 * enable the port
+	 */
+	UART_PUT_CR(port, PSIONW_UARTCR_UARTEN);
+
+	uartintm = UART_GET_INT_MASK(port);
+	uartintm |= PSIONW_UART_TXINT | PSIONW_UART_RXINT | PSIONW_UART_MSINT;
+	UART_PUT_INT_MASK(port, uartintm);
+
+	// Enable the irda for uart0
+	if (port->mapbase == PSIONW_UART0_V_BASE) {
+		cfg = UART_GET_CR(port);
+		cfg &= ~PSIONW_UARTCR_SIREN;
+		cfg |= PSIONW_UARTCR_IRTXM;	// power friendly tx encoding
+		UART_PUT_CR(port, cfg);
+
+#if 0
+		/*
+		 * Unblock irda rx while tx (full duplex)
+		 * Won't work with IrTTY because of 
+		 * duplicate packets
+		 */
+		cfg = readl(port->membase + PSIONW_UARTTR3);
+		cfg |= PSIONW_UARTTR3_IRUBLOCK;
+		writel(cfg, port->membase + PSIONW_UARTTR3);
+#endif
+
+	}
+
+	return 0;
+}
+
+static void
+psionwuart_shutdown(struct uart_port *port, struct uart_info *info)
+{
+	u_int syscon, pcdr;
+	u_int uartintm;
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, info);	/* UART interrupt */
+	uartintm = UART_GET_INT_MASK(port);
+	uartintm &= ~(PSIONW_UART_TXINT | PSIONW_UART_RXINT | PSIONW_UART_MSINT);
+	UART_PUT_INT_MASK(port, uartintm);
+
+	/*
+	 * disable the port
+	 */
+	UART_PUT_CR(port, 0);
+
+	/*
+	 * disable break condition and fifos
+	 */
+	UART_PUT_FCR(port, UART_GET_FCR(port) &
+		     ~(PSIONW_UARTFCR_UFIFOEN | PSIONW_UARTFCR_BREAK));
+
+	/*
+	 * Don't forget to disable port in PCDR
+	 */
+	pcdr = psionw_readl(PCDR);
+	if (port->mapbase == PSIONW_UART0_V_BASE) {
+		pcdr &= ~PCDR_UART1;
+	} else if (port->mapbase == PSIONW_UART1_V_BASE) {
+		pcdr &= ~PCDR_UART2;
+	}
+	psionw_writel(pcdr, PCDR);
+
+}
+
+static void
+psionwuart_change_speed(struct uart_port *port, u_int cflag,
+			u_int iflag, u_int quot)
+{
+	u_int fcr;
+	unsigned long flags;
+
+#if DEBUG
+	printk("psionwuart_set_cflag(0x%x) called\n", cflag);
+#endif
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	case CS5:
+		fcr = PSIONW_UARTFCR_WLEN_5;
+		break;
+	case CS6:
+		fcr = PSIONW_UARTFCR_WLEN_6;
+		break;
+	case CS7:
+		fcr = PSIONW_UARTFCR_WLEN_7;
+		break;
+	default:
+		fcr = PSIONW_UARTFCR_WLEN_8;
+		break;		// CS8
+	}
+	if (cflag & CSTOPB)
+		fcr |= PSIONW_UARTFCR_XSTOP;
+	if (cflag & PARENB) {
+		fcr |= PSIONW_UARTFCR_PRTEN;
+		if (!(cflag & PARODD))
+			fcr |= PSIONW_UARTFCR_EVENPRT;
+	}
+	if (port->fifosize > 1)
+		fcr |= PSIONW_UARTFCR_UFIFOEN;
+
+	port->read_status_mask = PSIONW_UARTRSR_OE;
+	if (iflag & INPCK)
+		port->read_status_mask |= PSIONW_UARTRSR_FE | PSIONW_UARTRSR_PE;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (iflag & IGNPAR)
+		port->ignore_status_mask |=
+		    PSIONW_UARTRSR_FE | PSIONW_UARTRSR_PE;
+	if (iflag & IGNBRK) {
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (iflag & IGNPAR)
+			port->ignore_status_mask |= PSIONW_UARTRSR_OE;
+	}
+
+	/*
+	 * Ignore all characters if CREAD is not set.
+	 */
+//	if ((cflag & CREAD) == 0)
+//		port->ignore_status_mask |= UART_DUMMY_RSR_RX;
+
+	/* first, disable everything */
+	save_flags(flags);
+	cli();
+
+	/* Set baud rate */
+	quot -= 1;
+	UART_PUT_LCR(port, quot);
+
+	/* Set the frame control */
+	UART_PUT_FCR(port, fcr);
+
+	restore_flags(flags);
+}
+
+/*
+ * Release the memory region(s) being used by 'port'
+ */
+static void
+psionwuart_release_port(struct uart_port *port)
+{
+	release_mem_region(port->mapbase, UART_PORT_SIZE);
+}
+
+/*
+ * Request the memory region(s) being used by 'port'
+ */
+static int
+psionwuart_request_port(struct uart_port *port)
+{
+	return request_region(port->mapbase, UART_PORT_SIZE, "serial_psionw")
+	    != NULL ? 0 : -EBUSY;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void
+psionwuart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_PSIONW;
+		psionwuart_request_port(port);
+	}
+}
+
+/*
+ * verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int
+psionwuart_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_PSIONW)
+		ret = -EINVAL;
+	if (ser->irq < 0 || ser->irq >= NR_IRQS)
+		ret = -EINVAL;
+	if (ser->baud_base < 9600)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops psionw_pops = {
+	tx_empty:	psionwuart_tx_empty,
+	set_mctrl:	psionwuart_set_mctrl,
+	get_mctrl:	psionwuart_get_mctrl,
+	stop_tx:	psionwuart_stop_tx,
+	start_tx:	psionwuart_start_tx,
+	stop_rx:	psionwuart_stop_rx,
+	enable_ms:	psionwuart_enable_ms,
+	break_ctl:	psionwuart_break_ctl,
+	startup:	psionwuart_startup,
+	shutdown:	psionwuart_shutdown,
+	change_speed:	psionwuart_change_speed,
+	release_port:	psionwuart_release_port,
+	request_port:	psionwuart_request_port,
+	config_port:	psionwuart_config_port,
+	verify_port:	psionwuart_verify_port,
+};
+
+static struct uart_port psionw_ports[UART_NR] = {
+	{
+	      membase:	(void *) PSIONW_UART0_V_BASE,
+	      mapbase:	PSIONW_UART0_V_BASE,
+	      iotype:	SERIAL_IO_MEM,
+	      irq:	IRQ_UART1,
+	      uartclk:	7372800,
+	      fifosize:	16,
+	      ops:	&psionw_pops,
+	      flags:	ASYNC_BOOT_AUTOCONF,
+	 },
+	{
+	      membase:	(void *) PSIONW_UART1_V_BASE,
+	      mapbase:	PSIONW_UART1_V_BASE,
+	      iotype:	SERIAL_IO_MEM,
+	      irq:	IRQ_UART2,
+	      uartclk:	7372800,
+	      fifosize:	16,
+	      ops:	&psionw_pops,
+	      flags:	ASYNC_BOOT_AUTOCONF,
+	 }
+};
+
+#ifdef CONFIG_SERIAL_PSIONW_CONSOLE
+/*
+ *	Print a string to the serial port trying not to disturb
+ *	any possible real use of the port...
+ *
+ *	The console_lock must be held when we get here.
+ *
+ *	Note that this is called with interrupts already disabled
+ */
+static void
+psionwuart_console_write(struct console *co, const char *s, u_int count)
+{
+	struct uart_port *port = psionw_ports + co->index;
+	unsigned int status, old_cr;
+	int i;
+
+	/*
+	 *	Ensure that the port is enabled.
+	 */
+	old_cr = UART_GET_CR(port);
+	UART_PUT_CR(port, PSIONW_UARTCR_UARTEN);
+
+	/*
+	 *	Now, do each character
+	 */
+	for (i = 0; i < count; i++) {
+		do {
+			status = UART_GET_FR(port);
+		} while (status & AMBA_UARTFR_TXFF);
+		UART_PUT_CHAR(port, s[i]);
+		if (s[i] == '\n') {
+			do {
+				status = UART_GET_FR(port);
+			} while (status & AMBA_UARTFR_TXFF);
+			UART_PUT_CHAR(port, '\r');
+		}
+	}
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore the uart state.
+	 */
+	do {
+		status = UART_GET_FR(port);
+	} while (status & AMBA_UARTFR_BUSY);
+
+	UART_PUT_CR(port, old_cr);
+}
+
+static kdev_t
+psionwuart_console_device(struct console *co)
+{
+	return MKDEV(SERIAL_PSIONW_MAJOR, SERIAL_PSIONW_MINOR + co->index);
+}
+
+static void __init
+psionwuart_console_get_options(struct uart_port *port, int *baud, int *parity,
+			       int *bits)
+{
+	if (UART_GET_CR(port) & PSIONW_UARTCR_UARTEN) {
+		u_int ubrfcr, quot;
+
+		ubrfcr = UART_GET_FCR(port);
+
+		*parity = 'n';
+		if (ubrfcr & PSIONW_UARTFCR_PRTEN) {
+			if (ubrfcr & PSIONW_UARTFCR_EVENPRT)
+				*parity = 'e';
+			else
+				*parity = 'o';
+		}
+
+		if ((ubrfcr & PSIONW_UARTFCR_WRDLEN_MASK) == PSIONW_UARTFCR_WLEN_7)
+			*bits = 7;
+		else
+			*bits = 8;
+		quot = UART_GET_LCR(port) & PSIONW_UART_BAUD_MASK;
+
+		*baud = port->uartclk / (16 * (quot + 1));
+	}
+}
+
+static int __init
+psionwuart_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port;
+	int baud = 38400;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	/*
+	 * Check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	port = uart_get_console(psionw_ports, UART_NR, co);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		psionwuart_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console psionw_console = {
+	name:	SERIAL_PSIONW_NAME,
+	write:	psionwuart_console_write,
+#ifdef used_and_not_const_char_pointer
+	read:	psionwuart_console_read,
+#endif
+	device:	psionwuart_console_device,
+	setup:	psionwuart_console_setup,
+	flags:	CON_PRINTBUFFER,
+	index:	-1,
+};
+
+void __init
+psionwuart_console_init(void)
+{
+	register_console(&psionw_console);
+}
+
+#define PSIONW_CONSOLE	&psionw_console
+#else				/* !CONFIG_SERIAL_PSIONW_CONSOLE  */
+#define PSIONW_CONSOLE	NULL
+#endif				/* !CONFIG_SERIAL_PSIONW_CONSOLE  */
+
+static struct uart_driver psionw_reg = {
+	owner:		THIS_MODULE,
+	normal_major:	SERIAL_PSIONW_MAJOR,
+#ifdef CONFIG_DEVFS_FS
+	normal_name:	SERIAL_PSIONW_NAME,
+	callout_name:	CALLOUT_PSIONW_NAME,
+#else
+	normal_name:	SERIAL_PSIONW_NAME,
+	callout_name:	CALLOUT_PSIONW_NAME,
+#endif
+
+	normal_driver:	&normal,
+	callout_major:	CALLOUT_PSIONW_MAJOR,
+	callout_driver:	&callout,
+
+	table:		psionw_table,
+	termios:	psionw_termios,
+	termios_locked:	psionw_termios_locked,
+
+	minor:		SERIAL_PSIONW_MINOR,
+	nr:		UART_NR,
+
+	port:		psionw_ports,
+	cons:		PSIONW_CONSOLE,
+};
+
+static int __init
+psionwuart_init(void)
+{
+	return uart_register_driver(&psionw_reg);
+}
+
+static void __exit
+psionwuart_exit(void)
+{
+	uart_unregister_driver(&psionw_reg);
+}
+
+module_init(psionwuart_init);
+module_exit(psionwuart_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR
+    ("Yuji Shinokawa <ysh@mob.or.jp> Tony Lindgren <tony@atomide.com>");
+MODULE_DESCRIPTION("Psion Windermere serial driver");
+MODULE_LICENSE("GPL");
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.h linux-2.4.19-rmk2/drivers/serial/serial_psionw.h
diff -urN -X /home/arm/dontdiff_tml_arm /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.h linux-2.4.19-rmk2/drivers/serial/serial_psionw.h
--- /home/download/kernels/linux-2.4.19-rmk2-vanilla/drivers/serial/serial_psionw.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.4.19-rmk2/drivers/serial/serial_psionw.h	2002-10-06 13:54:39.000000000 -0700
@@ -0,0 +1,93 @@
+/*
+ *  linux/drivers/char/serial_psionw.h
+ */
+
+/* Common with AMBA */
+#define AMBA_ISR_PASS_LIMIT	256
+#define AMBA_UARTIIR		0x1C	/* Same as Psion UARTINTR (Read only) */
+#define AMBA_UARTDR		0x00	/* Data read or written from the interface. */
+#define AMBA_UARTRSR		0x04	/* Receive status register (Read only). */
+#define AMBA_UARTFR_TXFF	0x20	/* Same as Psion UTXFF */
+#define AMBA_UARTFR_RXFE	0x10	/* Same as Psion URXFE */
+#define AMBA_UARTFR_BUSY	0x08	/* Same as Psion UBUSY */
+#define AMBA_UARTFR_DCD		0x04	/* Same as Psion DCD */
+#define AMBA_UARTFR_DSR		0x02	/* Same as Psion DSR */
+#define AMBA_UARTFR_CTS		0x01	/* Same as Psion CTS */
+#define AMBA_UARTFR_TMSK	(AMBA_UARTFR_TXFF + AMBA_UARTFR_BUSY)
+
+/* Psion specific port base addresses */
+#define PSIONW_UART0_BASE	(0x0600)
+#define PSIONW_UART1_BASE	(0x0700)
+#define PSIONW_UART0_V_BASE	(PSIONW_BASE + PSIONW_UART0_BASE)
+#define PSIONW_UART1_V_BASE	(PSIONW_BASE + PSIONW_UART1_BASE)
+
+/* Offsets from the base address for each port */
+#define PSIONW_UARTDR		(0x00)	/* Data register */
+#define PSIONW_UARTFCR		(0x04)	/* Frame control register */
+#define PSIONW_UARTLCR		(0x08)	/* Line control register, UBRCR */
+#define PSIONW_UARTCON		(0x0c)	/* Port control register */
+#define PSIONW_UARTFR		(0x10)	/* Flag register (Read only) UARTFLG */
+#define PSIONW_UARTINT		(0x14)	/* Second level interrupt register */
+#define PSIONW_UARTINTM		(0x18)	/* Interrupt mask register */
+#define PSIONW_UARTINTR		(0x1c)	/* Interrupt raw status register (Read only) */
+#define PSIONW_UARTTR1		(0x20)	/* Test register */
+#define PSIONW_UARTTR2		(0x24)	/* Test register */
+#define PSIONW_UARTTR3		(0x28)	/* Test register */
+
+#define PSIONW_UART_RXINT	(1 << 0)	/* Rx interrupt */
+#define PSIONW_UART_TXINT	(1 << 1)	/* Tx interrupt */
+#define PSIONW_UART_MSINT	(1 << 2)	/* Modem status interrupt */
+
+#define PSIONW_UART_BAUD_MASK	((1 << 16) - 1)
+#define PSIONW_UARTTR3_IRUBLOCK	(1 << 1)	/* Unblock irda rx */
+
+#define PSIONW_UARTCR_UARTEN	(1 << 0)	/* Uart enable */
+#define PSIONW_UARTCR_SIREN	(1 << 1)	/* SiR disable, clear to enable IrDA */
+#define PSIONW_UARTCR_IRTXM	(1 << 2)	/* IrDA Tx mode bit, set for power savings */
+
+#define PSIONW_UARTRSR_FE	(1 << 8)	/* Frame error */
+#define PSIONW_UARTRSR_PE	(1 << 9)	/* Parity error */
+#define PSIONW_UARTRSR_OE	(1 << 10)	/* Overrun error */
+
+#define PSIONW_UARTFCR_BREAK		(1 << 0)
+#define PSIONW_UARTFCR_PRTEN		(1 << 1)
+#define PSIONW_UARTFCR_EVENPRT		(1 << 2)
+#define PSIONW_UARTFCR_XSTOP		(1 << 3)
+#define PSIONW_UARTFCR_UFIFOEN		(1 << 4)
+#define PSIONW_UARTFCR_WLEN_5		(0 << 5)
+#define PSIONW_UARTFCR_WLEN_6		(1 << 5)
+#define PSIONW_UARTFCR_WLEN_7		(2 << 5)
+#define PSIONW_UARTFCR_WLEN_8		(3 << 5)
+#define PSIONW_UARTFCR_WRDLEN_MASK	(3 << 5)
+
+#define UART_PORT_SIZE		64
+
+#define PSIONW_UARTFR_MODEM_ANY	(AMBA_UARTFR_DCD|AMBA_UARTFR_DSR|AMBA_UARTFR_CTS)
+
+/* No modem break in Psion */
+#define PSIONW_UARTRSR_ANY	(PSIONW_UARTRSR_OE|PSIONW_UARTRSR_PE|PSIONW_UARTRSR_FE)
+
+#define UART_GET_INT_MASK(p)	readb((p)->membase + PSIONW_UARTINTM)
+#define UART_PUT_INT_MASK(p,c)	writeb((c), (p)->membase + PSIONW_UARTINTM)
+#define UART_CLEAR_INT(p,c)	writeb((c), (p)->membase + PSIONW_UARTINT)
+#define UART_GET_INT_STATUS(p)	readb((p)->membase + PSIONW_UARTINTR)
+
+#define UART_GET_FR(p)		readb((p)->membase + PSIONW_UARTFR)
+
+#define UART_GET_CR(p)		readb((p)->membase + PSIONW_UARTCON)
+#define UART_PUT_CR(p,c)	writeb((c), (p)->membase + PSIONW_UARTCON)
+
+#define UART_PUT_CHAR(p, c)	writeb((c), (p)->membase + AMBA_UARTDR)
+
+/* Must be readl for error bits */
+#define UART_GET_CHAR(p)	readl((p)->membase + AMBA_UARTDR)
+#define UART_RX_DATA(s)		(((s) & AMBA_UARTFR_RXFE) == 0)
+#define UART_TX_READY(s)	(((s) & AMBA_UARTFR_TXFF) == 0)
+#define UART_TX_EMPTY(p)	((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0)
+#define UART_GET_RSR(p)		readb((p)->membase + AMBA_UARTRSR)
+
+#define UART_GET_FCR(p)		readb((p)->membase + PSIONW_UARTFCR)
+#define UART_PUT_FCR(p,c)	writeb((c), (p)->membase + PSIONW_UARTFCR)
+
+#define UART_GET_LCR(p)		readl((p)->membase + PSIONW_UARTLCR)
+#define UART_PUT_LCR(p,c)	writel((c), (p)->membase + PSIONW_UARTLCR)
